本篇关于Activity启动模式相关的内容。
一、现象及说明
定义三个Activity:MainActivity、FirstActivity、SecondActivity。并按照上述的顺序依次启动这三个页面。manifest文件配置如下:
<activity android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="com.test"/>
<activity android:name=".FirstActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
当 SecondActivity 页面展示的时候。此时的栈组织情况是什么样的。
用 adb shell dumpsys activity activities
查看应用栈的使用情况。
➜ ~ adb shell dumpsys activity activities
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #1:
mResumedActivity=ActivityRecord{b23d936 u0 com.daddyno1.activityintentflagdemo/.SecondActivity t879}
Task id #879
...
* TaskRecord{a284dad #879 A=com.test U=0 StackId=1 sz=1}
userId=0 effectiveUid=u0a194 mCallingUid=u0a194 mUserSetupComplete=true mCallingPackage=com.daddyno1.activityintentflagdemo
affinity=com.test
intent={flg=0x10000000 cmp=com.daddyno1.activityintentflagdemo/.SecondActivity}
realActivity=com.daddyno1.activityintentflagdemo/.SecondActivity
...
* Hist #0: ActivityRecord{b23d936 u0 com.daddyno1.activityintentflagdemo/.SecondActivity t879}
packageName=com.daddyno1.activityintentflagdemo processName=com.daddyno1.activityintentflagdemo
launchedFromUid=10194 launchedFromPackage=com.daddyno1.activityintentflagdemo userId=0
app=ProcessRecord{ba1f8e2 22102:com.daddyno1.activityintentflagdemo/u0a194}
Intent { flg=0x10000000 cmp=com.daddyno1.activityintentflagdemo/.SecondActivity }
frontOfTask=true task=TaskRecord{a284dad #879 A=com.test U=0 StackId=1 sz=1}
taskAffinity=com.test
realActivity=com.daddyno1.activityintentflagdemo/.SecondActivity
...
realComponentName=com.daddyno1.activityintentflagdemo/.SecondActivity
Task id #878
...
* TaskRecord{e980473 #878 A=com.daddyno1.activityintentflagdemo U=0 StackId=1 sz=2}
userId=0 effectiveUid=u0a194 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.miui.home
affinity=com.daddyno1.activityintentflagdemo
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.daddyno1.activityintentflagdemo/.MainActivity}
realActivity=com.daddyno1.activityintentflagdemo/.MainActivity
...
* Hist #1: ActivityRecord{10ba47f u0 com.daddyno1.activityintentflagdemo/.FirstActivity t878}
packageName=com.daddyno1.activityintentflagdemo processName=com.daddyno1.activityintentflagdemo
launchedFromUid=10194 launchedFromPackage=com.daddyno1.activityintentflagdemo userId=0
app=ProcessRecord{ba1f8e2 22102:com.daddyno1.activityintentflagdemo/u0a194}
Intent { cmp=com.daddyno1.activityintentflagdemo/.FirstActivity }
frontOfTask=false task=TaskRecord{e980473 #878 A=com.daddyno1.activityintentflagdemo U=0 StackId=1 sz=2}
taskAffinity=com.daddyno1.activityintentflagdemo
realActivity=com.daddyno1.activityintentflagdemo/.FirstActivity
...
realComponentName=com.daddyno1.activityintentflagdemo/.FirstActivity
* Hist #0: ActivityRecord{c07acc u0 com.daddyno1.activityintentflagdemo/.MainActivity t878}
packageName=com.daddyno1.activityintentflagdemo processName=com.daddyno1.activityintentflagdemo
launchedFromUid=10023 launchedFromPackage=com.miui.home userId=0
app=ProcessRecord{ba1f8e2 22102:com.daddyno1.activityintentflagdemo/u0a194}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.daddyno1.activityintentflagdemo/.MainActivity bnds=[82,1305][250,1473] (has extras) }
frontOfTask=true task=TaskRecord{e980473 #878 A=com.daddyno1.activityintentflagdemo U=0 StackId=1 sz=2}
taskAffinity=com.daddyno1.activityintentflagdemo
realActivity=com.daddyno1.activityintentflagdemo/.MainActivity
...
realComponentName=com.daddyno1.activityintentflagdemo/.MainActivity
Running activities (most recent first):
TaskRecord{a284dad #879 A=com.test U=0 StackId=1 sz=1}
Run #2: ActivityRecord{b23d936 u0 com.daddyno1.activityintentflagdemo/.SecondActivity t879}
TaskRecord{e980473 #878 A=com.daddyno1.activityintentflagdemo U=0 StackId=1 sz=2}
Run #1: ActivityRecord{10ba47f u0 com.daddyno1.activityintentflagdemo/.FirstActivity t878}
Run #0: ActivityRecord{c07acc u0 com.daddyno1.activityintentflagdemo/.MainActivity t878}
mResumedActivity: ActivityRecord{b23d936 u0 com.daddyno1.activityintentflagdemo/.SecondActivity t879}
mLastPausedActivity: ActivityRecord{10ba47f u0 com.daddyno1.activityintentflagdemo/.FirstActivity t878}
根据 博文 这一篇的讲解,我们很容易看懂打印的信息,其中 Stack #1
就代表 ActivityStack。
一个 ActivityRecord实例 代表了一个 Activity实例,保存了Activity的所有信息,一个Activity可能会有多个ActivityRecord实例,因为可以被多次启动,跟具体启动模式有关。
一个 TaskRecord 由一个或多个 ActivityRecord 组成。它就是我们通常所说的任务栈,具有后进先出的特点。
一个应用可以有多个任务栈(TaskRecord),ActivityStack就是来管理 TaskRecord的。
这里的栈是概念上的,具体实现上可以有多种多样,源码里使用 ArrayList来实现。
二、管理任务
如果你想进行任务栈的管理,按照自己的想法组织 任务栈 和 页面的关系。你可以借助清单文件<activity>中的属性 以及 传递给 startActivity()的Intent中的Flag来实现上述目的,即可以使用这两种方式定义启动模式。
有些启动模式可以通过清单文件定义,但不能通过Intent标记定义。同样,有些启动模式可以通过Intent标记定义,却不能在清单中定义。
2.1 使用清单文件
standard
默认值。系统在启动该Activity的任务栈中创建Activity的新实例(不是绝对的,比如此时任务栈中的Activity是 singleInstance
,此时新建的standard
模式的Activity就一定会在其它的任务栈中),并将Intent传递给该实例。Activity可以多次实例化,每个实例可以属于不同任务栈。一个任务栈可以拥有多个实例。
singleTop
如果当前任务栈的栈顶已存在 Activity的实例,则系统会通过调用其onNewIntent
方法将 intent 转送给该实例,而不是创建新的实例。Activity 可以多次实例化,每个实例可以属于不同的任务,一个任务可以拥有多个实例。
singleTask
Activity 一次只能有一个实例存在。
1、如果任务栈中已存在该 Activity 的实例(可以是前台任务栈,也可以是后台任务栈。如果是后台的任务栈,会先将整个任务栈转到前台),则系统会调用onNewIntent
方法将 intent 转送到现有实例,同时将此Activity实例上边(后入栈)的 Activity全部弹出栈;
2、如果任务栈都不存在该 Activity的实例,如果已存在与 新Activity具有相同 affinity
的任务栈,则会将Activity启动到该任务中。如果不存在,则启动一个新的任务栈。
singleInstance
和 singleTask
类似,唯一不同的是:Activity 一次只能有一个实例存在,且该Activity 始终是其任务栈唯一的成员 ,所以由该 Activity启动的任何Activity都会在其他任务栈中打开。
以上的四种启动模式表现正常的前提是:使用默认Intent,没有添加任何Flag
2.2 使用Intent 标记
常用标记:
FLAG_ACTIVITY_SINGLE_TOP
、 FLAG_ACTIVITY_CLEAR_TOP
、 FLAG_ACTIVITY_NEW_TASK
写到这里,真的写不下去了,因为单问一个 Flag 的作用是没有意义的,Flag 和不同启动模式组合在一起,很可能会出现不同效果。我在做Demo测试的时候,想尽可能确定某一个Flag的作用,可能真的没办法,不同搭配有不同的效果,真的没办法说 某一个 Flag的作用。 这篇有点赞 所以一抓一大把讲启动模式的博文也不害羞,真是误人子弟。
举例1:使用 FLAG_ACTIVITY_NEW_TASK 开启一个页面时,如果目标Activity 的taskAffinity 和 当前任务栈的 affinity 相同,则不会新建任务栈,否则创建新的任务栈。如果启动Activity 或者 目标Activity 又跟singleInstance 有关的话,情况又会不一样。
举例2:FLAG_ACTIVITY_CLEAR_TOP
如果单独使用Intent.FLAG_ACTIVITY_CLEAR_TOP,并且没有设置特殊的launchMode,那么,Google官方的示例是:如果ABCD Task中的D采用Intent.FLAG_ACTIVITY_CLEAR_TOP唤起B,这个时候首先会将CD出栈,但是至于B是否会重建,要视情况而定,如果没有设置FLAG_ACTIVITY_SINGLE_TOP,则会将B finish掉,之后创建新的入栈。如果同时设置了FLAG_ACTIVITY_SINGLE_TOP,在当前栈已有的情况下就不会重建,而是直接回调B的onNewIntent。 同样,如果跟 singleInstance 组合的话效果又会不一样。
网友评论