【Android】四大组件之Activity

目录

一、什么是Activity

二、如何创建和配置Activity

[三、Activity 跳转与数据传递](#三、Activity 跳转与数据传递)

四、数据保存与恢复

[五、Activity 启动模式](#五、Activity 启动模式)

六、自定义返回行为

七、复杂界面布局


你可以把Activity想象成手机屏幕上的一个"页面"。比如,当你打开一个App时,看到的第一个界面就是一个Activity;点击某个按钮跳转到另一个界面,那就是另一个Activity。每个Activity就是一个独立的"屏幕",负责展示内容和与用户交互。

一、什么是Activity

Activity‌ 是 Android 应用的核心交互组件。

1‌. 单屏交互容器

  • 每个 Activity 对应一个独立的用户界面(UI)屏幕;
  • 此界面承载用户可见的视图控件,如按钮、文本框等;
  • 用户可在此界面进行交互操作,如点击、输入等。
  • 应用通常包含多个 Activity,通过跳转实现不同功能界面的切换。

2‌. 生命周期管理

onCreate():Activity被创建时调用。通常会在这里初始化界面和变量,这时我们看到的是一片空白。

onStart():Activity即将可见时调用。此后页面可见,但用户还不能跟页面进行互动。

onResume():Activity获得焦点,用户可以与之交互时调用。

onPause():Activity失去焦点时调用。比如,用户按了Home键回到桌面,或者跳转到另一个页面,但页面还没有完全不可见。

onStop():Activity不再可见时调用。比如,你点击文章详情页跳转到了文章里面。首页面被完全覆盖。

onRestart():Activity从停止状态重新启动时调用。首页Activity从后台回到前台,准备重新显示。

onDestroy():Activity被销毁时调用。比如,用户关闭了页面

3. 跨组件通信

  • 使用 ‌Intent‌ 与其他 Activity 或组件传递数据或启动新界面。
java 复制代码
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("key", "value");
startActivity(intent);

4. 关键功能

  • 用户事件处理‌:监听触摸、按键等操作,响应交互逻辑。
  • 界面动态更新‌:根据业务需求更新 UI 元素(如列表数据刷新)。
  • 资源管理 ‌:在 onDestroy() 中释放数据库连接、网络请求等资源,避免内存泄漏。

5. 门店与后厨模型

  • Activity 类似"门店"(直接面向用户),负责展示和接收指令;
  • Service 类似"后厨"(后台处理任务),通过 Intent("订单")传递需求。

二、如何创建和配置Activity

‌1. 手动创建 Activity

  • 在 Android Studio 中,右击包名 (如java/com/demo)→ New → Activity → Empty Activity,输入名称(如 MainActivity),取消勾选自动生成布局文件和主 Activity 选项。
  • 自动生成的类需继承 AppCompatActivity,并重写 onCreate() 方法:
java 复制代码
// java/com/demo/MainActivity.java
package com.demo

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 初始化组件和布局
    }

    @Override
    protected void onStart() {
        // Activity 可见但未获取焦点
    }

    @Override
    protected void onResume() {
        // 恢复交互,如重启动画
    }

    @Override
    protected void onPause() {
       // 暂停耗时操作,保存临时数据
    }

    @Override
    protected void onStop() {
       // 释放非必要资源
    }

    @Override
    protected void onDestroy() {
       // 清理线程、关闭数据库连接和网络请求、释放资源,避免内存泄漏
    }
}

2‌. 配置布局文件

  • res/layout 目录新建 XML 文件(如 activity_main.xml),定义 UI 元素。
  • 在 Activity 中通过 setContentView(R.layout.activity_main) 加载布局。
XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <!-- 顶部标题栏 -->
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:gravity="center"
        android:text="用户登录"
        android:textSize="24sp"
        android:background="#3F51B5"
        android:textColor="#FFFFFF"/>

    <!-- 输入区域 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">

        <EditText
            android:id="@+id/et_username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入用户名"
            android:inputType="text"/>

        <EditText
            android:id="@+id/et_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="12dp"
            android:hint="请输入密码"
            android:inputType="textPassword"/>

        <Button
            android:id="@+id/btn_login"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:layout_marginTop="24dp"
            android:text="立即登录"
            android:onClick="onLoginClick"
            android:backgroundTint="#2196F3"
            android:textColor="#FFFFFF"/>
    </LinearLayout>

    <!-- 底部操作区域 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="注册账号"
            android:textColor="#757575"/>

        <View
            android:layout_width="1dp"
            android:layout_height="16dp"
            android:layout_marginHorizontal="12dp"
            android:background="#BDBDBD"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="忘记密码"
            android:textColor="#757575"/>
    </LinearLayout>

</LinearLayout>

3. 注册 Activity

  • AndroidManifest.xml 中添加声明:
XML 复制代码
<activity
    android:name=".MainActivity"
    android:label="主界面">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

三、Activity 跳转与数据传递

1. 显式 Intent 跳转

java 复制代码
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("key", "value"); // 附加数据
startActivity(intent);

2.隐式 Intent 跳转

在目标 Activity 的 Manifest 中声明:

XML 复制代码
<activity android:name=".SecondActivity">
    <intent-filter>
        <action android:name="com.demo.action.ACTION_VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

调用代码:

java 复制代码
Intent intent = new Intent("com.demo.action.ACTION_VIEW");
startActivity(intent);

// 或者
Intent intent = new Intent();  
intent.setAction("com.demo.action.ACTION_VIEW");  
startActivity(intent);  

无需在代码中显式导入目标 Activity 的包名或类。

注意事项:

  • 必须包含 DEFAULT category ‌:隐式 Intent 的接收 Activity 需在 <intent-filter> 中声明 android.intent.category.DEFAULT,否则会触发 ActivityNotFoundException
  • 自定义 action 命名规范 ‌:如com.demo.action.ACTION_VIEW,避免与其他应用冲突。
  • 多应用匹配处理 ‌:若多个应用声明相同 action,系统会弹出选择器让用户选择目标应用。

3. 返回数据

使用 startActivityForResult() 启动 Activity,并在 onActivityResult() 处理返回数据。

  • MainActivity发送数据并启动新的SecondActivity。输入参数通过 Intent.putExtra() 传递。
java 复制代码
public class MainActivity extends AppCompatActivity {
    // 自定义请求标识符,用于区分不同Activity的返回结果
    private static final int REQUEST_CODE = 1001;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btnOpen = findViewById(R.id.btn_open);
        btnOpen.setOnClickListener(v -> {
            // 1. 创建显式 Intent
            Intent intent = new Intent(MainActivity.this, SecondActivity.class);
            
            // 2. 传递输入参数
            intent.putExtra("username", "admin");
            intent.putExtra("max_tries", 3);
            
            // 3. 启动并等待返回结果
            startActivityForResult(intent, REQUEST_CODE);
        });
    }

    // 4. 接收返回结果的回调方法
    @Override
    protected void onActivityResult(int requestCode,
                                    int resultCode,
                                    @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        
        if (requestCode == REQUEST_CODE) { // 匹配SecondActivity的返回结果
            if (resultCode == RESULT_OK && data != null) {
                // 5. 解析返回数据
                String result = data.getStringExtra("result_key");
                int score = data.getIntExtra("score", 0);
                
                // 6. 更新UI(示例:显示结果)
                TextView tvResult = findViewById(R.id.tv_result);
                tvResult.setText("结果: " + result + " 得分: " + score);
            } else {
                Toast.makeText(this, "用户取消操作", Toast.LENGTH_SHORT).show();
            }
        }
    }
}
  • SecondActivity接收数据并返回结果。返回数据通过 setResult() 返回。
java 复制代码
public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        // 1. 接收输入参数
        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            String username = extras.getString("username");
            int maxTries = extras.getInt("max_tries", 1);
            Log.d("DEBUG", "用户名: " + username + " 最大尝试次数: " + maxTries);
        }

        Button btnConfirm = findViewById(R.id.btn_confirm);
        btnConfirm.setOnClickListener(v -> {
            // 2. 创建返回数据的 Intent
            Intent resultIntent = new Intent();
            resultIntent.putExtra("result_key", "操作成功");
            resultIntent.putExtra("score", 85);
            
            // 3. 设置结果码并结束当前 Activity
            setResult(RESULT_OK, resultIntent);
            finish();
        });

        Button btnCancel = findViewById(R.id.btn_cancel);
        btnCancel.setOnClickListener(v -> {
            // 4. 用户取消操作的处理
            setResult(RESULT_CANCELED);
            finish();
        });
    }
}

结果码:

  • RESULT_OK:操作成功完成
  • RESULT_CANCELED:用户取消操作
  • 也可自定义数值(需使用 Activity.RESULT_FIRST_USER + N 格式)

4. 新版 Activity Result API

Google 推荐使用 ActivityResultContracts 替代传统方式startActivityForResult():

java 复制代码
// 在 Activity/Fragment 中初始化
ActivityResultLauncher<Intent> launcher = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == RESULT_OK) {
            Intent data = result.getData();
            // 处理返回数据
        }
    }
);

// 启动 Activity
launcher.launch(new Intent(this, SecondActivity.class));

四、数据保存与恢复

1‌. 临时数据保存

屏幕旋转等场景,需通过 onSaveInstanceState() 保存数据,并在重建时通过 onCreate()onRestoreInstanceState() 恢复。

java 复制代码
public class MainActivity extends AppCompatActivity {
    private static final String KEY_COUNTER = "counter";
    private static final String KEY_TEXT = "user_input";
    private static final String KEY_USER = "user_object";

    private int mCounter = 0;
    private EditText mEditText;
    private User mUser; // 假设 User 类实现了 Parcelable

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mEditText = findViewById(R.id.et_input);

        // 方式1:通过 onCreate 恢复(推荐)
        if (savedInstanceState != null) {
            mCounter = savedInstanceState.getInt(KEY_COUNTER, 0);
            mEditText.setText(savedInstanceState.getString(KEY_TEXT));
            mUser = savedInstanceState.getParcelable(KEY_USER);
            
            Log.d("RESTORE", "通过onCreate恢复数据");
        }
    }

    // 方式2:通过 onRestoreInstanceState 恢复(可选)
    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        
        // 此处的 Bundle 一定非空,无需判空
        String tempText = savedInstanceState.getString(KEY_TEXT);
        if (!TextUtils.isEmpty(tempText)) {
            mEditText.setText(tempText);
        }
        
        Log.d("RESTORE", "通过onRestoreInstanceState恢复数据");
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        
        // 保存基本类型
        outState.putInt(KEY_COUNTER, mCounter);
        
        // 保存用户输入
        outState.putString(KEY_TEXT, mEditText.getText().toString());
        
        // 保存自定义对象(需实现 Parcelable)
        if (mUser != null) {
            outState.putParcelable(KEY_USER, mUser);
        }
        
        Log.d("SAVE", "数据已保存");
    }

    // 示例按钮点击事件
    public void incrementCounter(View view) {
        mCounter++;
        TextView tvCounter = findViewById(R.id.tv_counter);
        tvCounter.setText(String.valueOf(mCounter));
    }
}

‌2. 持久化数据

建议在 onPause() 中执行保存操作。

特性 SharedPreferences SQLite
数据类型 简单键值对(基本类型、字符串) 结构化数据(支持复杂查询)
存储容量 适合小数据(KB级) 适合大数据(MB级)
查询能力 支持SQL查询、事务、索引
适用场景 用户设置、临时状态 用户生成内容、历史记录
性能表现 读写速度快 写操作较慢(需事务优化)

a. 使用 SharedPreferences 保存数据(适合简单配置)

java 复制代码
public class MainActivity extends AppCompatActivity {
    private static final String PREFS_NAME = "MyPrefs";
    private static final String KEY_USERNAME = "username";
    private static final String KEY_REMEMBER_ME = "remember_me";

    private EditText etUsername;
    private CheckBox cbRememberMe;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etUsername = findViewById(R.id.et_username);
        cbRememberMe = findViewById(R.id.cb_remember);

        // 从 SharedPreferences 加载数据
        SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
        etUsername.setText(prefs.getString(KEY_USERNAME, ""));
        cbRememberMe.setChecked(prefs.getBoolean(KEY_REMEMBER_ME, false));
    }

    @Override
    protected void onPause() {
        super.onPause();
        
        // 保存数据到 SharedPreferences
        SharedPreferences.Editor editor
            = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit();
        editor.putString(KEY_USERNAME, etUsername.getText().toString());
        editor.putBoolean(KEY_REMEMBER_ME, cbRememberMe.isChecked());
        editor.apply(); // 使用异步提交避免阻塞
    }
}

b. 使用 SQLite 保存数据(适合结构化数据)

数据库帮助类:

java 复制代码
public class UserDbHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "UserDatabase.db";
    private static final int DATABASE_VERSION = 1;

    // 用户表结构
    private static final String SQL_CREATE_ENTRIES =
        "CREATE TABLE " + UserContract.UserEntry.TABLE_NAME + " (" +
        UserContract.UserEntry._ID + " INTEGER PRIMARY KEY," +
        UserContract.UserEntry.COLUMN_NAME + " TEXT," +
        UserContract.UserEntry.COLUMN_EMAIL + " TEXT)";

    public UserDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(SQL_CREATE_ENTRIES);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 简单示例直接删除旧表
        db.execSQL("DROP TABLE IF EXISTS " + UserContract.UserEntry.TABLE_NAME);
        onCreate(db);
    }
}

数据操作实现:

java 复制代码
public class MainActivity extends AppCompatActivity {
    private EditText etName, etEmail;
    private UserDbHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        etName = findViewById(R.id.et_name);
        etEmail = findViewById(R.id.et_email);
        dbHelper = new UserDbHelper(this);
        
        loadDataFromDatabase();
    }

    private void loadDataFromDatabase() {
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor cursor = db.query(
            UserContract.UserEntry.TABLE_NAME,
            null, null, null, null, null, null
        );

        if (cursor.moveToFirst()) {
            etName.setText(cursor.getString(
                cursor.getColumnIndex(UserContract.UserEntry.COLUMN_NAME)));
            etEmail.setText(cursor.getString(
                cursor.getColumnIndex(UserContract.UserEntry.COLUMN_EMAIL)));
        }
        cursor.close();
    }

    @Override
    protected void onPause() {
        super.onPause();
        saveToDatabase();
    }

    private void saveToDatabase() {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        
        // 先清空旧数据(根据业务需求决定是否保留历史)
        db.delete(UserContract.UserEntry.TABLE_NAME, null, null);

        ContentValues values = new ContentValues();
        values.put(UserContract.UserEntry.COLUMN_NAME,
                   etName.getText().toString());
        values.put(UserContract.UserEntry.COLUMN_EMAIL,
                   etEmail.getText().toString());

        db.insert(UserContract.UserEntry.TABLE_NAME, null, values);
    }

    @Override
    protected void onDestroy() {
        dbHelper.close(); // 必须关闭数据库连接
        super.onDestroy();
    }
}

五、Activity 启动模式

模式 行为描述 典型场景
standard 默认模式,每次启动创建新实例入栈,即使已存在相同Activity。 普通页面跳转,如列表→详情
singleTop 若目标Activity在栈顶,直接复用,调用onNewIntent()。 避免重复推送,如通知栏点击
singleTask 若栈中存在目标Activity实例,清空其上方所有实例并移至栈顶;否则,新建实例。 应用主页(保证唯一性)
singleInstance 独占新任务栈,全局唯一实例;其他应用调用时直接复用。 独立功能模块,如系统相机、系统拨号界面

‌1. 标准模式(默认)

XML 复制代码
<activity android:name=".DetailActivity" />  <!-- 默认无需显式声明 -->

2. 栈顶复用模式

XML 复制代码
<activity 
    android:name=".NotificationActivity"
    android:launchMode="singleTop" />  <!-- 避免多次点击通知重复创建 -->

3. 任务栈内唯一模式

XML 复制代码
<activity 
    android:name=".MainActivity"
    android:launchMode="singleTask" />  <!-- 应用主入口 -->

4. 全局单例模式(很少用)

XML 复制代码
<activity 
    android:name=".CameraActivity"
    android:launchMode="singleInstance"  <!-- 声明为全局单例模式 -->
    android:taskAffinity="com.example.camera.task" />  <!-- 指定独立任务栈(可选) -->

注意:

  • 优先级冲突 ‌:若同时通过Intent标志(如FLAG_ACTIVITY_NEW_TASK)设置启动模式,Intent标志优先级高于AndroidManifest.xml配置。
  • 任务栈管理 ‌:singleTasksingleInstance模式会显著影响任务栈结构,需结合实际业务逻辑设计。

当前主流实践推荐:‌**核心页面(如主页)使用singleTask,高频复用页面(如通知页)使用singleTop**‌,以优化内存和用户体验。

六、自定义返回行为

基础自定义返回实现:

java 复制代码
public class MainActivity extends AppCompatActivity {
    private long backPressedTime = 0;

    @Override
    public void onBackPressed() {
        // 场景1:双击返回退出应用
        if (backPressedTime + 2000 > System.currentTimeMillis()) {
            super.onBackPressed(); // 执行默认返回
            finishAffinity();      // 关闭所有关联Activity
        } else {
            Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
        }
        backPressedTime = System.currentTimeMillis();

        // 场景2:Fragment返回栈处理
        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            getSupportFragmentManager().popBackStack();
        } else {
            super.onBackPressed(); // 必须调用父类方法
        }
    }
}

Android X推荐:

java 复制代码
// 在Activity或Fragment中使用
private OnBackPressedCallback callback = new OnBackPressedCallback(true) {
    @Override
    public void handleOnBackPressed() {
        // 自定义返回逻辑
        if (shouldInterceptBack()) {
            showExitConfirmation();
        } else {
            setEnabled(false); // 禁用当前回调
            requireActivity().onBackPressed(); // 触发系统返回
        }
    }
};

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 注册返回回调(推荐在Fragment中使用)
    requireActivity().getOnBackPressedDispatcher()
        .addCallback(this, callback);
}

七、复杂界面布局

1. Activity和Fragment

组件 Activity Fragment
核心生命周期方法 onCreate() onStart() onResume() onPause() onStop() onDestroy() 包含所有Activity方法,额外增加: onAttach() onCreateView() onDestroyView() onDetach()
特有方法 onAttach()(绑定宿主Activity) onCreateView()(创建UI视图) onDetach()(解绑宿主Activity)
独立性 独立组件,可直接运行 依附于宿主Activity,不可独立存在
组件定位 系统级交互单元(处理权限、窗口管理等) UI模块化组件(实现跨Activity界面复用与动态组合)

2. 典型架构

架构模式 适用场景 优势
单 Activity 架构 复杂导航流程、深度链接 统一管理导航、更好的状态恢复
多 Activity 架构 独立功能模块、不同任务栈需求 明确职责划分、方便权限管理
混合架构: 单Activity+多Fragment模式‌ ‌多模块Activity+多Fragment模式 大型项目、模块化开发 灵活组合、便于团队协作
相关推荐
_一条咸鱼_4 小时前
深度揭秘!Android HorizontalScrollView 使用原理全解析
android·面试·android jetpack
_一条咸鱼_4 小时前
揭秘 Android RippleDrawable:深入解析使用原理
android·面试·android jetpack
_一条咸鱼_4 小时前
深入剖析:Android Snackbar 使用原理的源码级探秘
android·面试·android jetpack
_一条咸鱼_4 小时前
揭秘 Android FloatingActionButton:从入门到源码深度剖析
android·面试·android jetpack
_一条咸鱼_4 小时前
深度剖析 Android SmartRefreshLayout:原理、源码与实战
android·面试·android jetpack
_一条咸鱼_4 小时前
揭秘 Android GestureDetector:深入剖析使用原理
android·面试·android jetpack
_一条咸鱼_4 小时前
深入探秘 Android DrawerLayout:源码级使用原理剖析
android·面试·android jetpack
_一条咸鱼_4 小时前
深度揭秘:Android CardView 使用原理的源码级剖析
android·面试·android jetpack
_一条咸鱼_4 小时前
惊爆!Android RecyclerView 性能优化全解析
android·面试·android jetpack
_一条咸鱼_4 小时前
探秘 Android RecyclerView 惯性滑动:从源码剖析到实践原理
android·面试·android jetpack