1.1.1. Activity
adb shell dumpsys activity activities
用于查看任务栈
1. launchMode启动模式
栈:先进后出
- Standard
标准模式。每次启动Activity都会创建新的实例。谁启动了这个Activity,那么这个Activity就运行在谁的Task中。==不能使用非Activity类型的context启动这种模式的Activity==, 因为这种context并没有Task,这个时候就可以加一个FLAG_ACTIVITY_NEW_TASK标记位,这个时候启动Activity实际上是以singleTask模式启动。
android.app.ContextImpl
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in.
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
}
- SingleTop 栈顶复用模式。如果当前栈顶是要启动的Activity,那么直接引用,如果不是,则新建。在直接引用的时候会调用onNewIntent()方法。
适合接收通知启动的内容显示页面,或者从外界可能多次跳转到一个界面。使用场景:浏览器的书签;通讯消息聊天界面
- SingleTask
栈内复用模式。这种模式下,只要Activity只要在一个栈内存在,那么就不会创建新的实例,会调用onNewIntent()方法。 如果要调用的Activity在同一应用中:调用singleTask模式的Activity会清空在它之上的所有Activity。 若其他应用启动该Activity:如果不存在,则建立新的Task。如果已经存在后台,那么启动后,后台的Task会一起被切换到前台。
适合作为程序入口点,例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
- SingleInstance
单实例模式。这时一种加强的singleTask,它除了具有singleTask的所有特性外,还加强了一点--该模式的Activity只能单独的位于一个Task中。 不同Task之间,默认不能传递数据(startActivityForResult()),如果一定要传递,只能使用Intent绑定。
使用场景:比如浏览器BrowserActivity很耗内存,很多app都会要调用它,这样就可以把该Activity设置成单例模式。比如:闹钟闹铃。适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。
- singleInstancePerTask
Android12 新增 待续
大部分情况等同于singleTask
singleInstancePerTask不需要为启动的Activity设置一个特殊的taskAffinity才能创建一个新的Task
该launchMode和Intent.FLAG_ACTIVITY_MULTIPLE_TASK或Intent.FLAG_ACTIVITY_NEW_DOCUMENT结合使用可以将启动的Activity在多个Task中多次实例化
这个Activity可以有多个实例,但是每个都是所在的Task的root Activity。
2.TaskAffinity
表示了一个Activity所需要的任务栈的名字,在默认情况下,如果不指定TaskAffinity属性,Activity所需任务栈的名字就是应用的名字。
启动模式为Standard下,单独使用TaskAffinity属性是无效的。
当TaskAffinity和SingleTask启动模式配对使用时,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中。
3.allowTaskReparenting
allowTaskReparenting属性的作用是Activity的迁移。当allowTaskReparenting属性和TaskAffinity配合使用时,Activity可以从一个任务栈迁移到另一个任务栈。
迁移的规则是:从一个与该Activity TaskAffinity属性不同的任务栈中迁移到与它TaskAffinity相同的任务栈中。
例如,如果电子邮件消息包含网页链接,则点击该链接会调出可显示该网页的 activity。该 activity 由浏览器应用定义,但作为电子邮件任务的一部分启动。如果将该 activity 的父项更改为浏览器任务,则它会在浏览器下一次转至前台时显示,在电子邮件任务再次转至前台时消失。
activity 的相似性由 taskAffinity
属性定义。通过读取任务根 activity 的相似性即可确定任务的相似性。因此,按照定义,根 activity 始终位于具有同一相似性的任务中。由于具有“singleTask
”或“singleInstance
”启动模式的 activity 只能位于任务的根上,因此更改父项仅限于“standard
”和“singleTop
”模式。(另请参阅 launchMode
属性。)
4.跟activity和Task 有关的 Intent启动方式有哪些?
核心的Intent Flag有:
- FLAG_ACTIVITY_NEW_TASK
- FLAG_ACTIVITY_CLEAR_TOP
- FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
- FLAG_ACTIVITY_SINGLE_TOP
FLAG_ACTIVITY_NEW_TASK
如果设置,这个Activity会成为历史stack中一个新Task的开始。一个Task(从启动它的Activity到下一个Task中的 Activity)定义了用户可以迁移的Activity原子组。Task可以移动到前台和后台;在某个特定Task中的所有Activity总是保持相同的次序。
使用这个标志,如果正在启动的Activity的Task已经在运行的话,那么,新的Activity将不会启动;代替的,当前Task会简单的移入前台。参考FLAG_ACTIVITY_MULTIPLE_TASK标志,可以禁用这一行为。 这个标志不能用于调用方对已经启动的Activity请求结果。
需要考虑到taskaffinity
FLAG_ACTIVITY_CLEAR_TOP
如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方的所有Activity都将关闭,然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中。 例如,假设一个Task中包含这些Activity:A,B,C,D。如果D调用了startActivity(),并且包含一个指向Activity B的Intent,那么,C和D都将结束,然后B接收到这个Intent,因此,目前stack的状况是:A,B。 上例中正在运行的Activity B既可以在onNewIntent()中接收到这个新的Intent,也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为 “multiple”(默认值),并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,那么它将关闭然后重新创建;对于其它的启动模式,或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,都将把这个Intent投递到当前这个实例的onNewIntent()中。 这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK结合起来使用:用于启动一个Task中的根Activity,它会把那个Task中任何运行的实例带入前台,然后清除它直到根Activity。这非常有用,例如,当从Notification Manager处启动一个Activity。
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
如果设置这个标志,这个activity不管是从一个新的栈启动还是从已有栈推到栈顶,它都将以the front door of the task的方式启动。这就讲导致任何与应用相关的栈都讲重置到正常状态(不管是正在讲activity移入还是移除),如果需要,或者直接重置该栈为初始状态。
FLAG_ACTIVITY_SINGLE_TOP
如果设置,当这个Activity位于历史stack的顶端运行时,不再启动一个新的 等于singleTop
5.通知栏下拉会导致Activity生命周期变化么?
不会,见onPause()的注释
6.两个Activity之间跳转时必然会执行的是哪几个方 法?
onResume/onPause 判断焦点
onStop onStart决定可见
一般情况下比如说有两个 activity,分别叫 A,B,当在 A 里面激活 B 组件的时候, A 会调用 onPause()方法,然后 B 调用 onCreate() ,onStart(), onResume()。 这个时候 B 覆盖了窗体, A 会调用 onStop()方法. 如果 B 是个透明的,或者 是对话框的样式, 就不会调用 A 的 onStop()方法。
7.横竖屏切换时Activity的生命周期(★★★★)
此时的生命周期跟清单文件里的配置有关系。 1.不设置 Activity 的 android:configChanges 时,切屏会重新调用各个生 命周期默认首先销毁当前 activity,然后重新加载。 2.设置 Activity android:configChanges="orientation|keyboardHidden|screenSize"时,切 屏不会重新调用各个生命周期,只会执行 onConfigurationChanged 方法。 通常在游戏开发, 屏幕的朝向都是写死的。
https://developer.android.com/guide/topics/manifest/activity-alias-element
http://leaking.github.io/android/(translate)Tasks-and-Back-Stack/
https://developer.android.com/guide/topics/manifest/activity-element