【Android】四大组件Activity

Activity基础概念

1. 定义与作用

  • Android 四大组件之一,是用户界面的载体,负责与用户交互。
  • 一个应用可包含多个 Activity,通过 Intent 切换。

2. 层次结构

  • Activity 通常放在 任务栈(Task Stack) 中管理,遵循后进先出(LIFO)原则。
  • 任务栈可跨应用,如从应用 A 启动应用 B 的 Activity,B 的 Activity 会加入 A 的任务栈。

3. Activity与Context的关系

  • Activity 是 Context 的子类,可直接使用 Context 的方法(如 getResources()startActivity())。
java 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Study"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

此元素的唯一必需属性是 [android:name],用于指定 activity 的类名称。您还可以添加属性 ,用于定义标签、图标或界面主题等 activity 特征。

Activity生命周期

一个 activity 在其生命周期中会经历多种状态。 您可以使用一系列回调来处理状态之间的转换。 developer.android.google.cn/guide/compo...

  • onCreate ():Activity 首次创建时调用,用于初始化组件、设置布局等
  • onStart ():Activity 即将可见时调用
  • onResume ():Activity 获得焦点、可交互时调用
  • onPause ():Activity 失去焦点、即将转入后台时调用
  • onStop ():Activity 完全不可见时调用
  • onRestart ():Activity 从停止状态重新启动时调用
  • onDestroy ():Activity 被销毁时调用

常见问题

  1. Android Activity 重复调用 onCreate () 的原因
  2. 跳转时未调用 onDestroy () 的核心原因
  3. 屏幕旋转时生命周期变化
  4. 屏幕旋转时的完整生命周期流程

Activity启动模式

在 Android 开发中,Activity 的启动模式(Launch Mode)、任务(Task)和返回栈(Back Stack)是实现应用导航逻辑的核心概念。理解这些机制对于构建流畅的用户体验和优化内存管理至关重要。

1. 四种启动模式

启动模式 核心特性 应用场景
standard 每次启动都创建新实例,无论目标 Activity 是否已存在于栈中 默认模式,普通页面跳转
singleTop 若目标 Activity 位于栈顶,则复用该实例;否则创建新实例 通知栏点击跳转、搜索结果页
singleTask 任务内单实例:若目标 Activity 存在于栈中,则清除其上方所有 Activity 应用主界面、浏览器主窗口
singleInstance 全局单实例:独占一个任务栈,不与其他 Activity 共存 系统级应用(如来电界面)

2. 启动模式设置

AndroidManifest.xml

java 复制代码
<activity
    android:name=".StandardActivity"
    android:launchMode="standard" />

Intent 标志位

标志位 作用
FLAG_ACTIVITY_NEW_TASK 类似 singleTask,通常用于从非 Activity 上下文启动 Activity
FLAG_ACTIVITY_SINGLE_TOP 类似 singleTop,启动时若目标 Activity 在栈顶则复用
FLAG_ACTIVITY_CLEAR_TOP 清除目标 Activity 上方的所有 Activity,通常与 NEW_TASK 配合使用
FLAG_ACTIVITY_REORDER_TO_FRONT 将已存在的 Activity 移至栈顶,不创建新实例
java 复制代码
Intent intent = new Intent(this, MainActivity.class); 
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 
startActivity(intent);

3. 启动模式示例

1. standard 模式

ini 复制代码
<activity
    android:name=".StandardActivity"
    android:launchMode="standard" />

行为 :每次启动都会创建新实例
任务栈变化

css 复制代码
初始栈:[MainActivity]
启动 StandardActivity:[MainActivity, StandardActivity]
再次启动:[MainActivity, StandardActivity, StandardActivity]

2. singleTop 模式

ini 复制代码
<activity
    android:name=".SingleTopActivity"
    android:launchMode="singleTop" />

行为

  • 若目标 Activity 在栈顶:调用 onNewIntent() 而非创建新实例
  • 若不在栈顶:创建新实例

任务栈变化

css 复制代码
初始栈:[MainActivity, SingleTopActivity]
再次启动 SingleTopActivity(在栈顶):[MainActivity, SingleTopActivity](复用)
启动其他 Activity:[MainActivity, SingleTopActivity, OtherActivity]
再次启动 SingleTopActivity(不在栈顶):[MainActivity, SingleTopActivity, OtherActivity, SingleTopActivity]

3. singleTask 模式

ini 复制代码
<activity
    android:name=".MainActivity"
    android:launchMode="singleTask"
    android:taskAffinity="com.example.app" />

行为

  • 若目标 Activity 不存在于任何任务:创建新任务并实例化
  • 若存在:将该任务移至前台,并清除其上方所有 Activity

任务栈变化

css 复制代码
初始栈:[MainActivity, ActivityB, ActivityC]
启动 MainActivity(已存在):[MainActivity](清除 B 和 C)

4. singleInstance 模式

ini 复制代码
<activity
    android:name=".SingleInstanceActivity"
    android:launchMode="singleInstance" />

行为

  • 目标 Activity 独占一个任务栈
  • 该任务栈中永远只有这一个 Activity

任务栈变化

css 复制代码
初始任务 Task1:[MainActivity]
启动 SingleInstanceActivity:
  Task1:[MainActivity]
  Task2:[SingleInstanceActivity]
从 SingleInstanceActivity 启动 ActivityB:
  Task1:[MainActivity, ActivityB]
  Task2:[SingleInstanceActivity]

Activity 数据传递与回调

1. 数据传递方式

  • Intent 携带数据
java 复制代码
// 创建 Intent 并添加参数
Intent intent = new Intent(CurrentActivity.this, TargetActivity.class);
intent.putExtra("key_string", "Hello World");  // 传递字符串
intent.putExtra("key_int", 123);               // 传递整数
intent.putExtra("key_boolean", true);          // 传递布尔值

// 传递自定义对象(需实现 Serializable 或 Parcelable 接口)
User user = new User("John", 25);
intent.putExtra("key_object", user);

// 启动 Activity
startActivity(intent);
java 复制代码
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_target);
    
    // 获取启动该 Activity 的 Intent
    Intent intent = getIntent();
    
    // 从 Intent 中获取参数
    String strValue = intent.getStringExtra("key_string");
    int intValue = intent.getIntExtra("key_int", 0);  // 第二个参数是默认值
    boolean boolValue = intent.getBooleanExtra("key_boolean", false);
    
    // 获取自定义对象
    User user = (User) intent.getSerializableExtra("key_object");
}
  • Bundle 传递复杂数据:
java 复制代码
// 创建 Bundle 对象并添加数据
Bundle bundle = new Bundle();
bundle.putString("name", "Alice");
bundle.putInt("age", 30);
bundle.putStringArrayList("hobbies", new ArrayList<>(Arrays.asList("reading", "swimming")));

// 将 Bundle 放入 Intent
Intent intent = new Intent(CurrentActivity.this, TargetActivity.class);
intent.putExtras(bundle);

// 启动 Activity
startActivity(intent);
java 复制代码
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_target);
    
    // 获取 Bundle
    Bundle bundle = getIntent().();
    if (bundle != null) {
        String name = bundle.getString("name");
        int age = bundle.getInt("age");
        ArrayList<String> hobbies = bundle.getStringArrayList("hobbies");
    }
}
  • 静态变量:通过静态类或单例模式存储数据。
  • ViewModel 共享数据 :在 Activity 间通过 ViewModel 共享数据(需配合 Jetpack)。

2. 数据回调方式

  • 旧方式(已弃用)onActivityResult() + startActivityForResult()
  • 新方式(Activity Result API)
java 复制代码
ActivityResultLauncher<Intent> launcher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> { if (result.getResultCode() == RESULT_OK) {
                    Intent data = result.getData();
                    // 处理返回数据
                    }
                });
// 启动 Activity
Intent intent = new Intent(this, SecondActivity.class);
launcher.launch(intent);

Activity UI 与布局

1. 加载布局的方式

  • setContentView(R.layout.activity_main):在 onCreate() 中加载布局文件。
  • 动态加载布局:
java 复制代码
LinearLayout root = findViewById(R.id.root_layout); 
View childView = LayoutInflater.from(this).inflate(R.layout.child_layout, root, false); 
root.addView(childView);

2. UI组件交互

  • 查找 View:findViewById() 或使用 Kotlin 的 by viewBindings
  • 设置监听器:
java 复制代码
Button button = findViewById(R.id.button); 
button.setOnClickListener(v -> { // 处理点击事件 });

3. Fragment 与 Activity 协作

  • Activity 中添加 Fragment:
java 复制代码
getSupportFragmentManager()
.beginTransaction() 
.add(R.id.fragment_container, new MyFragment()) 
.commit();
  • Fragment 与 Activity 通信:通过接口或 ViewModel

Activity状态管理

1. 临时状态保存

  • onSaveInstanceState(Bundle outState):在 Activity 可能被销毁前调用,保存临时数据(如文本框内容)。
  • onRestoreInstanceState(Bundle savedInstanceState):在 onCreate() 后恢复数据。
java 复制代码
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    // 获取保存的文本内容并恢复到文本框中
    String myText = savedInstanceState.getString("my_text");
    myEditText.setText(myText);
}
java 复制代码
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState != null) {
        // 恢复保存的数据
        String myText = savedInstanceState.getString("my_text");
        myEditText.setText(myText);
    }
}

2. 配置变更处理

  • 默认重建 :屏幕旋转等配置变更会导致 Activity 重建,需通过 savedInstanceState 恢复状态。
  • 禁止重建 :在 AndroidManifest.xml 中设置 android:configChanges="orientation|screenSize",并在 onConfigurationChanged() 中处理变更。
java 复制代码
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Log.d("MainActivity", "Orientation changed to Landscape");
        setContentView(R.layout.activity_main_landscape);
        // 恢复EditText的内容
        if (savedUsername != null) {
            etUsername = findViewById(R.id.et_username); // 需要重新获取EditText引用
            etUsername.setText(savedUsername);
        }
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Log.d("MainActivity", "Orientation changed to Portrait");
        setContentView(R.layout.activity_main);
        // 恢复EditText的内容
        if (savedUsername != null) {
            etUsername = findViewById(R.id.et_username); // 重新获取EditText引用
            etUsername.setText(savedUsername);
        }
    }
}

Activity常见问题

  1. Activity 生命周期的各个阶段及其作用?
  2. 屏幕旋转时 Activity 的重建过程及如何避免?
  3. Activity 启动模式的区别和应用场景?
  4. 如何在 Activity 间传递大数据(超过 1MB)?
  5. Activity 和 Fragment 的关系与区别?
  6. 如何优化 Activity 的启动速度?
相关推荐
踢球的打工仔1 天前
PHP面向对象(7)
android·开发语言·php
安卓理事人1 天前
安卓socket
android
安卓理事人1 天前
安卓LinkedBlockingQueue消息队列
android
万能的小裴同学1 天前
Android M3U8视频播放器
android·音视频
q***57741 天前
MySql的慢查询(慢日志)
android·mysql·adb
JavaNoober1 天前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android
城东米粉儿1 天前
关于ObjectAnimator
android
zhangphil1 天前
Android渲染线程Render Thread的RenderNode与DisplayList,引用Bitmap及Open GL纹理上传GPU
android
火柴就是我1 天前
从头写一个自己的app
android·前端·flutter
lichong9511 天前
XLog debug 开启打印日志,release 关闭打印日志
android·java·前端