Android 的任务栈 Task 与启动模式

什么是任务

任务是用户在执行某项工作时与之互动的一系列 Activity 的集合。这些 Activity 按照每个 Activity 打开的顺序排列在一个返回堆栈中。

如何管理任务 

启动模式定义 Activity 的新实例如何与当前任务关联。可以借助 清单元素中的属性以及传递给 startActivity() 的 intent 中的标记来实现任务的关联方式。

如何查看当前系统的任务栈 

  1. 手机中点击多任务键 可以看到系统当前的任务栈。

  2. 命令行中  adb shell dumpsys activity  查看以下关键内容

...  
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
...
   Running activities (most recent first):
   TaskRecord{386481f #782 A=com.testintent_1 U=0 StackId=1 sz=1}
     Run #1: ActivityRecord{e60b18e u0 com.testintent/.MainActivity t782}
   TaskRecord {120576c #781 A=com.testintent U=0 StackId=1 sz=1}
     Run #0: ActivityRecord{bdb842e u0 com.testintent/.CoverActivity t781}
...

有两个任务栈:com.testintent 和 com.testintent_1。

Activity 启动模式

1. standard 默认模式。系统在启动该 Activity 的任务中创建一个新实例,并将 intent 传送给该实例。Activity 可以多次实例化,每个实例可以属于不同的任务,一个任务可以拥有多个实例。

2. singleTop 如果当前任务的顶部已存在 Activity 的实例,则系统会通过调用其 onNewIntent() 方法来将 intent 转送给该实例,而不是创建 Activity 的新实例。Activity 可以多次实例化,每个实例可以属于不同的任务,一个任务可以拥有多个实例(但前提是返回堆栈顶部的 Activity 不是该 Activity 的现有实例)。

  • singleTop模式,只在当前任务栈中生效。

  • 如果通过 startActivityForResult 启动一个设置了 singleTop 的 activity,singleTop 模式将无效。

3.  singleTask 当一个具有 singleTask 模式的 Activity 请求启动,系统首先会寻找是否存在 Activity 想要的任务栈(taskAffinity 标识 Activity 所需的任务栈的名字,默认情况下是应用的包名),如果不存在,就创建一个新任务栈,然后创建 A 的实例放入栈中。如果存在所需任务栈,有实例存在,就把 A 上面的 Activity 全部出栈,并将 intent 传送给该实例的 onNewIntent() 方法,如果实例不存在,就创建实例并放入栈中。

  • TaskAffinity 属性主要和 singleTask 启动模式或 allowTaskReparenting 属性配对使用。如果应用 A 启动应用 B allowTaskReparenting 为 true 的Activity,那么当应用 B 启动,此 Activity 会从 A 的任务栈转移到应用 B 的任务栈。

再具体点:A  应用启动 B  应用的 ActivityC,然后按 home 键回到桌面,再单击 B 应用的图标,这时启动的不是 B 的主 Activity,而是重新显示了 A 应用启动的 ActivityC,C 从 A 的任务栈转移到了 B 的任务栈。

  • 当作为 startActivityForResult 启动的目标时:

1. 4.x版本.会立刻在上个 activity 中 onActivityResult 中返回一个为 cancel 的 resultCode。(不管新的 activity 是否是在新的任务栈中启动) 。

2. 5.x版本.不管是否定义了 taskAffinity,都会把将要被启动的 activity 的启动模式忽略,onActivityResult 方法会正常回调。

4. singleInstance 与 "singleTask" 相似,唯一不同的是系统不会将任何其他 Activity 启动到包含该实例的任务中。该 Activity 始终是其任务唯一的成员;由该 Activity 启动的任何 Activity 都会在其他的任务中打开。

onNewIntent() 使用注意

方法体中需手动调用 setIntent(intent),否则之后的 getIntent() 获取的都是旧的 intent 对象。

常用的 Intent Flag

1. FLAG_ACTIVITY_NEW_TASK

...
 * If set, this activity will become the start of a new task on this history stack.
 ...
 * When using this flag, if a task is already running for the activity
 * you are now starting, then a new activity will not be started; instead,
 * the current task will simply be brought to the front of the screen with
 * the state it was last in.  See {@link #FLAG_ACTIVITY_MULTIPLE_TASK} for a flag
 * to disable this behavior.
 * This flag can not be used when the caller is requesting a result from the activity being launched.
 ...

如果设置了,此活动将成为此历史堆栈上新任务的开始。当使用这个 flag 时,如果 task 中已经有了你要启动的 Activity ,就不再启动一个新的 Activity;当前 task 会被带到前台。可以用 FLAG_ACTIVITY_MULTIPLE_TASK 使这种行为无效。当调用者 startActivityForResult() 时,不能使用此标志。

比如栈中情况是 A,B,C,在 C 中启动 D,如果在 Manifest.xml 文件中给 D 添加了 Affinity(默认是包名) 的值和 C 所在的 Task 中的不一样,则会在新标记的 Affinity 所存在的 Task 中看 D 是否已经启动,如果已经启动直接将 D 所在的 task 带入到前台,否则直接将 activity 启动;如果是默认的或者指定的 Affinity 和 Task 一样,就和标准模式一样启动一个新的 Activity。此 flag 与启动模式 singleTask 效果不太一样,对于非 Activity 启动的 Activity(比如Service或者通知中启动的Activity)需要显示的设置 Intent.FLAG_ACTIVITY_NEW_TASK。

  1. FLAG_ACTIVITY_CLEAR_TOP
...
 * If it has declared its launch mode to be "multiple" (the
 * default) and you have not set {@link #FLAG_ACTIVITY_SINGLE_TOP} in
 * the same intent, then it will be finished and re-created; for all other
 * launch modes or if {@link #FLAG_ACTIVITY_SINGLE_TOP} is set then this
 * Intent will be delivered to the current instance's onNewIntent().
 ...

如果申明了 launch mode 是 "multiple" (默认情况就是)且没有在同一个 Intent 中设置 FLAG_ACTIVITY_SINGLE_TOP,Activity 将会结束且重新创建(回调 onCreate 生命周期方法);对于其他所有的 launch modes 或者设置了 FLAG_ACTIVITY_SINGLE_TOP,Intent 将被分发给实例的 onNewIntent() 方法。

比如栈中情况是 A,B,C,D,在 D 中启动 B(加入该flag), 栈中的情况将为 A,B,B 会执行 onCreate() ...。如果希望与 launch mode 中 singleTask 效果相同执行 onNewIntent(),可以同时加上 FLAG_ACTIVITY_SINGLE_TOP。

3. FLAG_ACTIVITY_SINGLE_TOP 


* If set, the activity will not be launched if it is already running`` 
* at the top of the history stack.

如果设置,如果此 activity 已经在历史堆栈的顶部将不会被启动。

相当于 launch mode 的 singleTop,比如栈中情况是 A,B,C,D,在 D 中启动D(加入该flag),栈中的情况还是 A,B,C,D。

4. FLAG_ACTIVITY_CLEAR_TASK

* If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
 * this flag will cause any existing task that would be associated with the
 * activity to be cleared before the activity is started.  That is, the activity
 * becomes the new root of an otherwise empty task, and any old activities
 * are finished.  This can only be used in conjunction with {@link #FLAG_ACTIVITY_NEW_TASK}.

如果在一个 Intent 中设置,会导致在此 activity 开启之前,任何与该 activity 相关的 task 都会被清除。此 activity 将会是一个空 task 的最底部的 activity,之前所有的 activities 将被结束,此 flag 只能与 FLAG_ACTIVITY_NEW_TASK 配合使用。

5. FLAG_ACTIVITY_REORDER_TO_FRONT

* If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
 * this flag will cause the launched activity to be brought to the front of its
 * task's history stack if it is already running.
 * For example, consider a task consisting of four activities: A, B, C, D.
 * If D calls startActivity() with an Intent that resolves to the component
 * of activity B, then B will be brought to the front of the history stack,
 * with this resulting order:  A, C, D, B.
 * This flag will be ignored if {@link #FLAG_ACTIVITY_CLEAR_TOP} is also
 * specified.

如果在 Intent 中设置 ,如果待启动的 activity 已经开启在运行了,此 flag 将使其位于任务历史堆栈的前面。例如栈中情况是 A,B,C,D,如果 D 启动 B,栈中将变成A,C,D,B (B 将回调 onNewIntent() )。如果 FLAG_ACTIVITY_CLEAR_TOP 也被指定,此标志将被忽略。

6. FLAG_ACTIVITY_FORWARD_RESULT  

* If set and this intent is being used to launch a new activity from an
 * existing one, then the reply target of the existing activity will be
 * transferred to the new activity.  This way, the new activity can call
 * {@link android.app.Activity#setResult} and have that result sent back to
 * the reply target of the original activity.

如果在 Intent 中设置此 flag 从现有的 activity 去开启一个新的 activity ,现有的 activty 将会把回复的目标转移给新 activity. 新 activity 可以调用 setResult() 将结果发送给现有 activity 的回复目标。

例如:A 通过 startActivityForResult 启动 B,B 启动 C,但 B 为过渡页可以 finish 了,A 在期望 C 把结果返回。这种情况,B 可以在启动 C 的时候加入该flag。

7. FLAG_ACTIVITY_PREVIOUS_IS_TOP

* If set and this intent is being used to launch a new activity from an existing one
 ...
 * The previous activity will
 * be used as the top, with the assumption being that the current activity
 * will finish itself immediately.

如果当前的 activity 在开启新 activity 的 intent 设置此 flag, 当前 activity 之前的 activity 将被当视为 top,当前的 activity 将立即结束。

例如:栈中情况 A,B,C,C 启动 D 时使用此标志,在启动时 C 不会被当成栈顶 Activity,而是 B 作为栈顶启动 D,然后 C 会 finish()。经常与 FLAG_ACTIVITY_FORWARD_RESULT 一起配合使用。

8. FLAG_ACTIVITY_NO_HISTORY

* If set, the new activity is not kept in the history stack.  As soon as
* the user navigates away from it, the activity is finished.  This may also
* be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory
* noHistory} attribute.
* If set, {@link android.app.Activity#onActivityResult onActivityResult()}
* is never invoked when the current activity starts a new activity which
* sets a result and finishes.

如果设置了此 flag,开启的 activity 将不会存在历史堆栈中。一旦用户离开它,activity 就结束了。也可以用{@link android.R来设置。styleable # AndroidManifestActivity_noHistory noHistory}属性。如果设置了此 flag,activity 将不会回调 onActivityResult()。

9. FLAG_ACTIVITY_TASK_ON_HOME  

Intent passed to {@link Context#startActivity Context.startActivity()},
* this flag will cause a newly launching task to be placed on top of the current
* home activity task (if there is one).  That is, pressing back from the task
* will always return the user to home even if that was not the last activity they
* saw. This can only be used in conjunction with {@link #FLAG_ACTIVITY_NEW_TASK}.

如果 intent 中设置此 flag 将使新启动的 task 置于当前 home activity 任务之上(如果有的话)。也就是说,从任务中返回总是会将用户返回到home,即使这不是他们看到的最后一个 activity。此 flag 只能与 FLAG_ACTIVITY_NEW_TASK 配合使用。

10. FLAG_EXCLUDE_STOPPED_PACKAGES   

* If set, this intent will not match any components in packages that
* are currently stopped.  If this is not set, then the default behavior
* is to include such applications in the result.

如果设置,intent 将与当前停止的包中的任何组件不匹配。如果未设置此flag,则默认行为是在结果中包含此类应用程序。

参考资料

  • https://developer.android.com/guide/components/activities/tasks-and-back-stack?hl=zh-cn
  • Android API 29 Platform

https://mp.weixin.qq.com/s/V1pPrW1UAz13lJU3rlLfNA

kkFileView

使用spring boot打造文件文档在线预览项目解决方案,支持doc、docx、ppt、pptx、xls、xlsx、zip、rar、mp4,mp3以及众多类文本如txt、html、xml、java、properties、sql、js、md、json、conf、ini、vue、php、py、bat、gitignore等文件在线预览

发布于:4天以前  |  37次阅读  |  详细内容 »

谷歌确认将推出新功能 对标苹果AirDrop

北京时间7月1日早间消息,据外媒报道,此前几个月中一直有传言称谷歌将为Android手机添加一个类似苹果AirDrop的新功能。如今,谷歌终于证实,他们的确将推出这个功能,其正式名称为“Nearby Share”。一些Android手机用户已经测试了该功能的beta版本。

发布于:11天以前  |  55次阅读  |  详细内容 »

老干妈回应:腾讯公司被骗了 并没有与腾讯有任何的合作

6月30日,中国裁判文书网显示,广东省深圳市南山区人民法院发布一则民事裁定书,同意原告腾讯请求查封、冻结被告老干妈公司公司名下价值人民币16240600元的财产。但6月30日下午,老干妈声明称,经核实,公司从未与腾讯或授权他人与腾讯就“老干妈”品牌签署《联合市场推广合作协议》,且从未与腾讯进行过任何商业合作。

发布于:11天以前  |  57次阅读  |  详细内容 »

移动端常见崩溃指标

崩溃分析,是将 Android 和 iOS 平台常见的 APP 崩溃问题进行归类分析,帮助企业根据崩溃指标快速发现、定位问题。

发布于:12天以前  |  128次阅读  |  详细内容 »

58同城一季度净利润16.386亿元,同比增134.7%

6月26日讯,生活服务平台58同城(NYSE:WUBA)公布了截至2020年3月31日第一季度未经审计的财务报告。财报显示,58同城第一季度实现营收25.603亿元,同比下滑15.5%;净利润16.386亿元,同比增134.7%。

发布于:14天以前  |  56次阅读  |  详细内容 »

马斯克豪宅以2900万美元出手,买家为网易CEO丁磊

6月20日早间消息,据《华尔街日报》周五援引公开记录报道,特斯拉首席执行官埃隆·马斯克(Elon Musk)以2900万美元的价格出售了他在洛杉矶Bel-Air地区的一处房屋。报道称,买家是与中国亿万富翁丁磊有联系的公司。

发布于:21天以前  |  89次阅读  |  详细内容 »

甲骨文公司泄露数十亿条网络数据记录

据外媒报道,科技巨头「甲骨文」的数据管理平台BlueKai因为在服务器上不加密码从而泄露了全球数十亿条数据记录。甲骨文发言人黛博拉·海林格(Deborah Hellinger)对媒体表示,该消息属实。

发布于:21天以前  |  80次阅读  |  详细内容 »

罗永浩:筹备脱口秀节目,正在组建团队

6月21日晚间消息,极客公园与哔哩哔哩联合举办的Rebuild2020科技全明星峰会上,罗永浩在对话中透露,自己准备在一个比较大的平台上做一档综艺节目,是一档脱口秀节目,当下正在组建团队。“做这一档节目不是为了赚钱。”罗永浩说。

发布于:21天以前  |  76次阅读  |  详细内容 »

最多阅读

简化Android的UI开发 8月以前  |  201298次阅读
Android设计与开发工作流 7月以前  |  2349次阅读
Google Enjarify:可代替dex2jar的dex反编译 1年以前  |  2338次阅读
Android多渠道打包工具:apptools 1年以前  |  1968次阅读
Android权限 - 第一篇 1年以前  |  1922次阅读
Google Java编程风格规范(中文版) 1年以前  |  1908次阅读
Stetho 1年以前  |  1839次阅读
Android UI基本技术点 1年以前  |  1836次阅读
30分钟搭建一个android的私有Maven仓库 1年以前  |  1817次阅读
2015 Google IO带来的新 Android 开发工具 1年以前  |  1729次阅读
你应该知道的布局和属性 1年以前  |  1685次阅读
听FackBook工程师讲*Custom ViewGroups* 1年以前  |  1679次阅读
Gradle小知识#3:任务的顺序 1年以前  |  1654次阅读
MVP在Android平台上的应用 1年以前  |  1654次阅读