Android 四大组件——Activity

目录

[一、Activity 基础概念](#一、Activity 基础概念)

[二、Activity 生命周期](#二、Activity 生命周期)

[1. 生命周期回调方法](#1. 生命周期回调方法)

[2. 生命周期场景](#2. 生命周期场景)

[触发或不触发 onPause/onStop 的 UI 组件(本质是附属的还是独立的)](#触发或不触发 onPause/onStop 的 UI 组件(本质是附属的还是独立的))

[三、Activity / ActionBarActivity / AppCompatActivity的区别:](#三、Activity / ActionBarActivity / AppCompatActivity的区别:)

四、onCreate()一个参数和两个参数的区别:

详细对比分析

1.单参数代码示例

2.双参数代码示例

五、Activity间的数据相互传递

六、关闭所有Activity和退出App

1.关闭所有Activity

2.退出App

七、屏幕旋转对Activity的影响

[1.使用 onSaveInstanceState() 保存临时状态(最常用)](#1.使用 onSaveInstanceState() 保存临时状态(最常用))

2.手动处理配置变更(阻止销毁重建)

[3.固定 Activity 屏幕方向的方法](#3.固定 Activity 屏幕方向的方法)

[3.1 在 AndroidManifest.xml 中配置(推荐)](#3.1 在 AndroidManifest.xml 中配置(推荐))

[3.2 在 Java 代码中动态设置](#3.2 在 Java 代码中动态设置)

[4.使用 ViewModel + LiveData(架构组件推荐)](#4.使用 ViewModel + LiveData(架构组件推荐))

与其他方案的对比

八、启动模式

九、设置Activity全屏的方法

1.代码隐藏ActionBar

2.通过requestWindowFeature设置

3.通过AndroidManifest.xml的theme


一、Activity 基础概念

Activity 是 Android 应用的核心组件之一,它代表一个单一的、用户可交互的屏幕。Activity可以理解成一个绘制用户界面的窗口, 而这个窗口可以填满整个屏幕,也可能比屏幕小或者浮动在其他窗口的上方!

注意:必须在 AndroidManifest.xml 文件中进行声明。

二、Activity 生命周期

这是 Activity 最核心的概念,它描述了 Activity 从创建到销毁的整个过程。系统通过调用一系列生命周期回调方法来管理 Activity。

1. 生命周期回调方法

  • onCreate()必须实现 。Activity 第一次创建时 调用。在此进行一次性初始化,如加载布局 (setContentView)、绑定数据等。

  • onStart():Activity 对用户可见之前调用。此时 Activity 已进入前台,但可能还无法与用户交互(例如被一个对话框部分覆盖)。

  • onResume():Activity 开始与用户交互之前调用。此时 Activity 位于 Activity 堆栈的顶部,接收用户输入。应用的核心功能通常在这里恢复。

  • onPause():当系统准备启动或恢复另一个 Activity 时调用。在此应提交未保存的更改、释放占用资源的系统组件(如广播接收器),但操作要轻量快速,否则会拖慢下一个 Activity 的启动。

  • onStop():Activity 对用户完全不可见时调用。可以执行重量级的关闭操作,如将数据写入数据库。

  • onRestart():在 onStop() 之后,Activity 重新启动 时调用,后接 onStart()

  • onDestroy():Activity被销毁之前调用。这是 Activity 收到的最后一个回调。可能是因为 Activity 正常结束,也可能是因为系统为节省空间而将其销毁。

2. 生命周期场景

  • 正常启动:A onCreate -> A onStart -> A onResume

  • 打开新 Activity B(A 完全被覆盖):A onPause -> B onCreate -> B onStart -> B onResume -> A onStop

  • 从 B 返回 A:B onPause -> A onRestart -> A onStart -> A onResume -> B onStop -> B onDestroy

  • 按返回键退出 A:A onPause -> A onStop -> A onDestroy

  • 屏幕旋转/配置更改当前 Activity 会被销毁并重建。A onPause -> A onStop -> A onDestroy -> A onCreate -> A onStart -> A onResume

另外AlertDialog和PopWindow是不会触发onPause(),onStop()回调方法!!!

AlertDialogPopupWindow 默认不会触发其所属 Activity 的 onPause()onStop() 回调。 这是因为它们被系统归类为同一窗口内部的UI元素 ,而不是一个新的、独立的"用户界面"。它们附着在所属 Activity 的窗口之上 。它们与 Activity 共享同一个 "UI上下文""焦点栈"

触发或不触发 onPause/onStop 的 UI 组件(本质是附属的还是独立的)

组件类型 默认行为 原因
Activity 触发下层 Activity 的 onPause/onStop 创建了新的顶级窗口,抢夺了焦点和可见性。
AlertDialog, PopupWindow, DialogFragment 不触发 onPause/onStop 附属窗口,与 Activity 共享同一UI上下文和焦点栈。
Spinner, Menu, Snackbar, Toast 不触发 onPause/onStop 属于应用内弹出的临时UI,本质是 PopupWindow 或系统提示。
配置为系统悬浮窗的 PopupWindow 触发 onPause/onStop 窗口类型改变为 TYPE_SYSTEM_ALERT 等,成为独立的顶级窗口

三、Activity / ActionBarActivity / AppCompatActivity的区别:

  • Activity :是 Android 框架原始的、最基础的基类。

  • ActionBarActivity :是 过时 的 Support Library 类,用于在旧版 Android 上实现 Material Design 风格的 ActionBar。

  • AppCompatActivity :是 现代、官方推荐 的 Support Library / AndroidX 类,用于在旧版 Android 上实现 Material Design 及其最新特性 ,是 ActionBarActivity 的直接替代品。

简单来说,它们的演进路径是:Activity -> ActionBarActivity (已废弃) -> AppCompatActivity (当前标准)。

下面我们通过一个表格和详细解释来说明三者的区别。

特性 Activity (原生) ActionBarActivity (已废弃) AppCompatActivity (现代)
所属库 android.app.Activity (Android Framework) android.support.v7.app.ActionBarActivity (Old Support Library) android.support.v7.app.AppCompatActivity (Old Support Lib) androidx.appcompat.app.AppCompatActivity (AndroidX)
引入目的 提供基本的 Activity 组件功能。 在 Android 3.0 (API 11) 之前版本上提供 ActionBar 兼容支持。 提供更全面的 Material Design 特性向后兼容,并成为应用的基础类。
ActionBar API 11+ 原生支持。 主要功能:在低版本上提供 ActionBar。 提供并增强了 ActionBar 支持,并演变为 Toolbar 的官方支持载体。
Material Design API 21+ 原生支持。 有限的 Material Design 样式。 完整支持 :将 Material Design 样式和组件(如 Toolbar)向后兼容到 API 7+。
主题要求 可以使用任何主题,如 Theme.Material 必须使用/继承 Theme.AppCompat 系列主题。 必须使用/继承 Theme.AppCompat 系列主题。
现状与建议 仍在使用,但对于需要 Material Design 一致性的应用不推荐。 完全废弃。不应在新项目中使用,老项目应迁移。 官方强烈推荐现代开发的标准选择

"为了兼容低版本" 是 AppCompatActivity 最核心、最根本的设计目标和存在意义。

四、onCreate()一个参数和两个参数的区别:

  • onCreate(Bundle savedInstanceState):这是你最常见、必须实现标准生命周期方法 。即使两个参数的onCreate()实现了,也需要实现onCreate(Bundle savedInstanceState)。

  • onCreate(Bundle savedInstanceState, PersistableBundle persistentState):这是一个可选的重载方法 ,用于支持 "持久性" 的 Activity,允许它在设备重启后仍能恢复状态。在实际开发中极少使用。

详细对比分析

特性 onCreate(Bundle savedInstanceState) onCreate(Bundle savedInstanceState, PersistableBundle persistentState)
方法签名 一个参数 两个参数
API 级别 从 API 1 开始存在 API 21 (Android 5.0) 开始引入
使用场景 所有 Activity 的标准入口点。用于处理常规的初始化,如设置布局、绑定数据。 仅用于声明了 android:persistableMode="persistAcrossReboots" 的 Activity。
数据恢复范围 恢复因 配置变更系统资源紧张被杀死 时的临时状态。 除了恢复上述状态,还能恢复在 设备关机再开机(重启) 后的持久状态。
数据持久性 临时性。数据保存在内存中,系统杀死进程后,这些数据就丢失了。 持久性。数据会写入磁盘,即使设备重启,数据依然存在。
适用情况 绝大多数应用场景。如恢复编辑框的文本、列表的滚动位置等。 极少数特殊场景。如系统设置、Launcher、或需要记录用户操作流程且不怕重启的应用。
如何保存数据 onSaveInstanceState(Bundle outState) 中保存数据。 除了 onSaveInstanceState,还需要在 onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) 中保存持久化数据。

1.单参数代码示例

java 复制代码
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    EditText editText = findViewById(R.id.editText);

    // 检查是否有之前保存的状态需要恢复
    if (savedInstanceState != null) {
        String savedText = savedInstanceState.getString("KEY_EDIT_TEXT");
        editText.setText(savedText);
    }
}

// 必须重写此方法来保存临时状态
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("KEY_EDIT_TEXT", editText.getText().toString());
}

2.双参数代码示例

要使用这个重载方法,你必须先在 AndroidManifest.xml 中为该 Activity 声明一个属性

XML 复制代码
<activity
    android:name=".MyPersistableActivity"
    android:persistableMode="persistAcrossReboots" />

两个 Bundle 参数的区别

  • savedInstanceState:和单参数版本一样,用于存储临时性状态

  • persistentState:这是一个 PersistableBundle 对象,用于存储持久性状态 。这个状态会被写入磁盘的 /data/system/procstats 目录下,即使设备关机再开机,这个数据依然存在。

java 复制代码
// 在 AndroidManifest.xml 中声明了 android:persistableMode="persistAcrossReboots"
public class MyPersistableActivity extends AppCompatActivity {

    private int mPersistentCounter = 0;

    @Override
    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        setContentView(R.layout.activity_persistable);

        // 从 persistentState 中恢复持久化数据
        if (persistentState != null) {
            mPersistentCounter = persistentState.getInt("PERSISTENT_COUNTER", 0);
        }

        Button button = findViewById(R.id.button);
        button.setOnClickListener(v -> {
            mPersistentCounter++;
            // 持久化数据不会自动保存,需要手动触发
            // 通常会在 onPause 或 onStop 中调用 onSaveInstanceState
        });
    }

    // 重写此方法来保存持久化数据
    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        // 将需要持久化的数据存入 outPersistentState
        outPersistentState.putInt("PERSISTENT_COUNTER", mPersistentCounter);
    }
}

单参数的 onCreate 是用来"恢复现场"的,而双参数的 onCreate 是用来"时光倒流"的

五、Activity间的数据相互传递

传递:A-->B

在使用Bundle传递数据时,要注意,Bundle的大小是有限制的 < 0.5MB,如果大于这个值 是会报TransactionTooLargeException异常的!!!

传回:A<--B

这个在之前的 Intent 章节提到过,相关内容可以查看上一章。

六、关闭所有Activity和退出App

1.关闭所有Activity

有时我们可能会打开了很多个Activity,突然来个这样的需求,在某个页面可以关掉 所有的Activity并退出程序!好吧,下面提供一个关闭所有Activity的方法, 就是用一个list集合来存储所有Activity。

java 复制代码
public class ActivityCollector {  
    public static LinkedList<Activity> activities = new LinkedList<Activity>();  
    public static void addActivity(Activity activity)  
    {  
        activities.add(activity);  
    }  
    public static void removeActivity(Activity activity)  
    {  
        activities.remove(activity);  
    }  
    public static void finishAll()  
    {  
        for(Activity activity:activities)  
        {  
            if(!activity.isFinishing())  
            {  
                activity.finish();  
            }  
        }  
    }  
}  

2.退出App

java 复制代码
/** 
 * 退出应用程序 
 */  
public void AppExit(Context context) {  
    try {  
        ActivityCollector.finishAll(); 
        //暴力杀死后台进程 
        ActivityManager activityMgr = (ActivityManager) context  
                .getSystemService(Context.ACTIVITY_SERVICE);  
        activityMgr.killBackgroundProcesses(context.getPackageName());  
        System.exit(0);  
    } catch (Exception ignored) {}  
}  

调用 killBackgroundProcesses() 方法,传入当前应用的包名,强制杀死该应用的所有后台进程

七、屏幕旋转对Activity的影响

屏幕旋转是 配置变更 中最典型的例子,当发生旋转后会销毁与重建。

出现的问题:

  • Activity 中所有非持久化的成员变量和数据都会丢失,因为对象被销毁了。
  • 用户体验中断:正在播放的视频、动画会中断,滚动列表的位置会重置,输入框的焦点会丢失等。

1.使用 onSaveInstanceState() 保存临时状态(最常用)

这是最基本也是必须掌握的方案。系统在销毁 Activity之前会调用此方法,让你有机会保存临时状态。

java 复制代码
//保存状态
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState); // 必须调用父类方法!
    // 将需要恢复的数据存入Bundle
    outState.putInt("KEY_SCORE", mCurrentScore);
    outState.putString("KEY_INPUT_TEXT", mUserInputText);
}


//恢复状态
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 检查是否有之前保存的状态
    if (savedInstanceState != null) {
        mCurrentScore = savedInstanceState.getInt("KEY_SCORE", 0);
        mUserInputText = savedInstanceState.getString("KEY_INPUT_TEXT", "");

        // 恢复UI状态,比如设置EditText的文本
        EditText editText = findViewById(R.id.editText);
        editText.setText(mUserInputText);
    }
}

注意: onSaveInstanceState 主要用于保存轻量级的、瞬时的 UI 状态。不适合保存大量数据(如Bitmap)或需要持久化的数据。

2.手动处理配置变更(阻止销毁重建)

你可以告知系统:"这个配置变更由我自己处理,你不要销毁我的 Activity"。

在 AndroidManifest.xml 中为 Activity 配置 android:configChanges属性。

XML 复制代码
<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|keyboardHidden" />
  • orientation:屏幕方向

  • screenSize:屏幕尺寸(API 13以上必需,因为旋转也涉及尺寸变化)

  • keyboardHidden:键盘可用性改变

效果:

  • 设置之后,屏幕旋转时 Activity 不会被销毁重建

  • 取而代之,系统会调用**onConfigurationChanged(Configuration newConfig)**方法。

java 复制代码
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        // 切换到横屏,可以在这里手动调整UI
        Log.d("Orientation", "Now in Landscape");
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        // 切换到竖屏
        Log.d("Orientation", "Now in Portrait");
    }
}

优缺点:

  • 优点:Activity 不会重建,所有成员变量都得以保留,用户体验无缝。

  • 缺点

    • 你必须自己处理所有UI更新 。例如,如果你为横竖屏准备了不同的布局(layout-landlayout-port),系统不会自动切换,你需要手动调用 setContentView 并重新初始化所有视图,这非常繁琐且容易出错。

    • 不推荐作为常规解决方案,仅适用于确实不希望UI被重建的特殊场景 (如游戏、摄像头预览)。假如在特定场景下使用,如打开后必须使用横屏/竖屏。我们就可以看看下面的方法。

3.固定 Activity 屏幕方向的方法

3.1 在 AndroidManifest.xml 中配置(推荐)

这是最常用、最简洁的方式,在应用清单文件中为 Activity 声明屏幕方向。

XML 复制代码
<activity
    android:name=".MainActivity"
    android:screenOrientation="portrait" /> <!-- 固定为竖屏 -->


<activity
    android:name=".MainActivity"
    android:screenOrientation="landscape" /> <!-- 固定为横屏 -->

3.2 在 Java 代码中动态设置

java 复制代码
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 固定为竖屏
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        
        // 或者固定为横屏
        // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        
        setContentView(R.layout.activity_main);
    }
}

4.使用 ViewModel + LiveData(架构组件推荐)

这是 现代 Android 开发中最推荐、最优雅的解决方案ViewModel 的设计目的就是存放和管理与UI相关的数据,并且它的生命周期比 Activity 更长。

ViewModel 在配置变更(如旋转)中会存活下来!

java 复制代码
// 1. 创建ViewModel
public class MyViewModel extends ViewModel {
    private MutableLiveData<Integer> currentScore = new MutableLiveData<>(0);
    private MutableLiveData<String> userInput = new MutableLiveData<>("");

    public LiveData<Integer> getCurrentScore() {
        return currentScore;
    }

    public void setScore(int score) {
        currentScore.setValue(score);
    }

    public LiveData<String> getUserInput() {
        return userInput;
    }

    public void setUserInput(String input) {
        userInput.setValue(input);
    }
}

// 2. 在Activity中使用
public class MainActivity extends AppCompatActivity {
    private MyViewModel viewModel;

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

        // 获取ViewModel(如果是旋转后重建,会拿到同一个实例)
        viewModel = new ViewModelProvider(this).get(MyViewModel.class);

        // 观察LiveData,数据变化时自动更新UI
        viewModel.getCurrentScore().observe(this, score -> {
            TextView scoreView = findViewById(R.id.scoreView);
            scoreView.setText("Score: " + score);
        });

        viewModel.getUserInput().observe(this, input -> {
            EditText editText = findViewById(R.id.editText);
            if (!editText.getText().toString().equals(input)) {
                editText.setText(input);
            }
        });

        findViewById(R.id.button).setOnClickListener(v -> {
            // 更新ViewModel中的数据,观察者会自动触发UI更新
            viewModel.setScore(viewModel.getCurrentScore().getValue() + 1);
        });
    }
}

优势:

  • 数据与UI分离 :Activity 只负责显示和交互,数据由 ViewModel 持有。

  • 自动生命周期管理:无需手动保存和恢复,代码更简洁。

  • 完美的数据持久性:屏幕旋转对用户完全无感,数据一直都在。

与其他方案的对比

方案 适用场景 实现复杂度 用户体验
固定屏幕方向 不需要横竖屏切换的应用 ⭐☆☆☆☆ (非常简单) 一致但不够灵活
onSaveInstanceState 需要保存简单状态的应用 ⭐⭐☆☆☆ (简单) 有短暂的中断
ViewModel 现代应用,数据驱动的UI ⭐⭐⭐☆☆ (中等) 几乎无缝
configChanges 特殊场景,如游戏、相机 ⭐⭐⭐⭐☆ (复杂) 完全无缝

八、启动模式

接下来我们来详细地讲解下四种加载模式: 他们分别是:standard (默认),singleTopsingleTasksingleInstance

在 AndroidManifest.xml 中通过 android:launchMode 设置。

  1. standard(默认):每次启动都会创建一个新的 Activity 实例。一个任务中可以有多个相同 Activity 的实例。

  2. singleTop :如果要启动的 Activity 已经位于任务栈顶 ,则不会创建新实例,而是调用其 onNewIntent() 方法。否则创建新实例。适用于防止重复启动同一个界面(如通知点击)。

  3. singleTask :系统会创建一个新任务 ,并将该 Activity 实例化为新任务的根 Activity。如果该 Activity 的实例已存在于一个独立的任务中,系统会将该任务转到前台,并调用 onNewIntent()一个任务中只存在一个该 Activity 的实例。常用于应用的主页。

  4. singleInstance :与 singleTask 类似,但持有该 Activity 的任务只能有这一个 Activity 。任何从该 Activity 启动的新 Activity 都会在另一个任务中打开。适用于需要单独任务栈的场景(如闹钟)。

使用 Intent Flag 动态控制

你也可以在 Intent 中设置 Flag 来动态控制启动行为,其优先级高于 launchMode

  • FLAG_ACTIVITY_NEW_TASK:在新任务中启动 Activity。

  • FLAG_ACTIVITY_SINGLE_TOP:等同于 singleTop

  • FLAG_ACTIVITY_CLEAR_TOP:如果目标 Activity 已在当前任务中,则会销毁位于它之上的所有 Activity,使其位于栈顶。

九、设置Activity全屏的方法

1.代码隐藏ActionBar

在Activity的onCreate方法中调用getActionBar.hide();即可

2.通过requestWindowFeature设置

requestWindowFeature(Window.FEATURE_NO_TITLE); 该代码需要在setContentView ()之前调用,不然会报错!!!

注: 把 requestWindowFeature(Window.FEATURE_NO_TITLE);放在super.onCreate(savedInstanceState);前面就可以隐藏ActionBar而不报错。

3.通过AndroidManifest.xml的theme

在需要全屏的Activity的标签内设置 theme = @android:style/Theme.NoTitleBar.FullScreen

相关推荐
TimeFine3 小时前
Android 网络请求超时?可能与连接池和脏连接有关
android
Digitally5 小时前
如何将安卓手机备份到电脑?7种方法
android
火柴就是我6 小时前
android:enableJetifier=true 再学习
android·flutter
杨筱毅6 小时前
【Android】【底层原理】深入解析SELinux模块
android·底层机制
Tom4i6 小时前
基于 Launcher3 的 iOS 风格桌面 04 拖拽和移位
android
2501_915106326 小时前
iOS 反编译防护工具与实战组合 从静态侦察到 IPA 成品加固的工程化路径
android·ios·小程序·https·uni-app·iphone·webview
游戏开发爱好者89 小时前
iOS 26 iPhone 使用记录分析 多工具组合构建全方位设备行为洞察体系
android·ios·小程序·uni-app·cocoa·iphone·webview
zhangphil16 小时前
HARDWARE 属性的Bitmap与普通Bitmap,GPU与RenderThread渲染与处理方式异同比较,Android
android
消失的旧时光-194318 小时前
Flutter 异步编程:Future 与 Stream 深度解析
android·前端·flutter