【Android】活动的生命周期、启动模式及标记位

一、 生命周期

Android使用Task管理活动,一个任务就是一组存放在栈里的活动集合,被叫做返回栈

启动新活动时入栈,并处于栈顶位置,销毁活动时,栈顶元素出栈。

系统总是会显示处于栈顶的活动。

活动状态

1.运行状态:当活动位于栈顶时,处于运行状态

2.暂停状态:当活动不再处于栈顶位置,但仍然可见时,活动进入暂停状态

3.停止状态:当活动不再处于栈顶位置并且完全不可见时,活动进入停止状态。

4.销毁状态:活动从返回栈中移除。

正常情况下的生命周期

活动的生存期

Activity类中定义了7种回调方法

java 复制代码
onCreate():每个活动都重写,在活动第一次被创建时调用。
onStart():在活动由不可见变为可见时调用,可见,但不在前台无法交互
onResume():在活动准备好和用户交互时调用,此时活动位于栈顶并处于运行状态,可见并在前台出现
onPause():在系统准备启用或恢复另一个活动时调用,释放资源并保留关键数据
onStop():在活动完全不可见时调用
onDestory():在活动销毁前调用,之后活动变为销毁状态
onRestart():在活动由停止状态变为运行状态时调用

完整生存期:在onCreate和onDestory之间经历,活动在onCreate初始化在onDestory释放内存。

可见生存期:在onStart和onStop之间经历,管理对用户可见资源,在onStart加载资源,在onStop释放资源

前台生存期:在onResume和onPause之间经历,在前台生存期内活动总处于运行状态,此时活动可以和用户交互。

复制代码
**正常切换到桌面或打开新Activity**
onPause->onStop
**如果新Activity采用透明主题**
不回调onStop
**当打开新Activity**
先执行旧Activity的onPause再启动新Activity

异常情况下的生命周期

1.资源相关的系统配置发生改变导致Activity被杀死并重新创建

例如配置了横屏和竖屏两种资源文件,当旋转屏幕时,由于系统配置发生改变,在默认情况下,Activity会被销毁并重新创建

此时属于异常情况下终止,系统会调用onSaveInstanceState保存当前Activity的状态(在onStop之前);重新创建Activity后,系统会调用onRestoreInstanceState,将onSaveInstanceState方法保存的Bundle对象作为参数传递给onRestoreInstanceState(onStart之后调用)和onCreate

在异常情况下需要重建时,系统会为我们保留Activity的当前视图结构,再重启后恢复这些数据(如文本框中输入的内容,ListView的滚动位置等)。

每一个View都有onSaveInstanceState和onRestoreInstanceState,其中的具体实现就是系统自动为View保留的数据。

保存和恢复View的层级结构:Activity调用onSaveInstanceState->Activity委托Window保存数据->Window委托它上面的顶级容器(ViewGroup,一般是DecorView)保存数据->顶层容器一一通知子元素保存数据**(典型委托思想,上层委托下层,父容器委托子元素,应用:View的绘制,事件分发)**

onRestoreInstanceState和onCreate获取保存数据的区别:onRestoreInstanceState一旦被调用,其参数Bundle一定有值,不必判空;onCreate正常启用Bundle为null需要额外判断。

系统只会在Activity即将被销毁并有重新显示的机会时才会调用onSaveInstanceState

2.资源内存不足导致其优先级低的Activity被杀死

Activity的优先级(从高到低):前台Activity(正在和用户交互的Activity)->可见但非前台Activity(如对话框)->后台Activity(已被暂停)

当内存不足时,系统会杀死优先级低的Activity所在进程,后续通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。

将后台工作放入Service中保证有一定的优先级,保证不会被系统回收。

3.不想重新创建Activity,指定configChanges属性

在AndroidMenifest.xml中加入Activity的声明

configChanges的常见项目及其含义

复制代码
locale:设置的本地位置发生了改变,一般指切换了系统语言
orientation:屏幕方向发生改变,如旋转了屏幕
keyboardHidden:键盘的可访问性发生了改变,如用户调出键盘
screenSize:屏幕尺寸信息发生了改变,当编译选项中的minSdkVersion和targetSdkVersion均低于13时不会重启Activity
smallScreenSize:设备的物理屏幕尺寸发生改变,当编译选项中的minSdkVersion和targetSdkVersion均低于13时不会重启Activity

系统不重新创建,会调用onConfigurationChanged方法

二、 活动的启动模式

分别为standard,singleTop,singleTask和singleInstance,可以在AndroidManifext.xml中通过给标签指定android:launchMode属性选择启动模式

standard

默认启动模式,启动新活动时都会在返回栈中入栈并处于栈顶位置,系统不会在乎活动是否已经在栈中存在,每次启动都会创建该活动的新实例。

谁启用了这个Activity就会进入启用他的Activity的所在栈。使用非Activity类型的Context没有任务栈,此时会报错,需要为待启动Activity指定FLAG_ACTIVITY_NEW_TASK标记位,会为他重新创建一个任务栈。

singleTop

在启动活动时如果返回栈的栈顶已经是该活动,则不会创建新实例。当该活动不是栈顶时,依然会创建新实例。

复制代码
<activity
            android:name=".FirstActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:label="This is FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

此时会调用Activity的onNewIntent方法

singleTask

启动活动时系统首先检查栈中是否存在该活动的实例,发现存在直接使用该实例,并把在这个活动之上的活动都出栈,没有则创建新的活动实例。此时会调用Activity的onNewIntent方法。

复制代码
<activity
            android:name=".FirstActivity"
            android:exported="true"
            android:launchMode="singleTask"
            android:label="This is FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

singleInstance

会启用一个新的单独的返回栈来管理这个活动,不管哪个应用程序来访问这个活动,都有一个共同的返回栈

复制代码
 <activity
            android:name=".FirstActivity"
            android:exported="true"
            android:launchMode="singleInstance"
            android:label="This is FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

Activity所需任务栈

TaskAffinity: 任务相关性,标识了Activity所需任务栈的名字,默认情况下所有Activity的所需任务栈名字为应用的包名

可以为每个Activity单独指定TaskAffinity属性,为了和singleTask启动模式或allowTaskReparenting属性配对使用。

任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity位于暂停状态

allowTaskReparenting 是一个在 AndroidManifest.xml 的 <activity> 标签中设置的属性。它控制着一个 Activity 在不同 任务(Task) 之间的"转移"能力。

当应用A启用了应用B的某个Activity时,当allowTaskReparenting属性为true时,当应用B被启动,此Activity会从应用A的任务栈转到应用B的任务栈

简单来说:

当一个应用 A 启动了一个原本"属于"应用 B 的 Activity 时,这个被启动的 Activity 可以选择"认祖归宗",从应用 A 的任务栈转移到应用 B 的任务栈中,特别是当应用 B 被切换到前台时。

指定启动模式的两种方式:

1.通过AndroidMenifest的launchMode指定

2.通过在Intent中设置标志位指定

复制代码
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

2的优先级大于1,第二种方法无法为Activity指定singleInstance模式

三、 活动的的标记位

标记位的作用:设定Activity的启动模式,影响Activity的运行状态。

标记位的常见参数如下

复制代码
FLAG_ACTIVITY_NEW_TASK:为Activity指定singleTask启动模式
FLAG_ACTIVITY_SINGLE_TOP:为Activity指定singleTop启动模式
FLAG_ACTIVITY_CLEAR_TOP:Activity启动时,在同一个任务栈中所有位于他上面的Activity都要出栈;如果被启动的Activity采用standard模式启动,它和它之上的Activity都要出栈,系统会创建新的实例入栈
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:这个Activity不会出现在历史Activity列表中
相关推荐
WAsbry3 小时前
InputConnection机制与跨进程文本操作的工程实践
android·linux
WAsbry3 小时前
Android输入法框架的Binder通信机制剖析
android
WAsbry3 小时前
从一个Bug看Android文本编辑的设计缺陷
android·linux
沐怡旸3 小时前
【底层机制】Android低内存管理机制深度解析
android
wuwu_q4 小时前
用通俗易懂 + Android 开发实战的方式讲解 Kotlin Flow 中的 filter 操作符
android·开发语言·kotlin
stevenzqzq6 小时前
Android Hilt 入门教程_注解汇总
android
峰哥的Android进阶之路7 小时前
Android的binder机制理解
android·binder
弥巷7 小时前
【Android】Android内存缓存LruCache与DiskLruCache的使用及实现原理
android·java
fool_hungry8 小时前
Android MotionEvent ACTION_OUTSIDE 详细解释
android