Activity 登堂入室
1.Activity,Window 与 View 的关系
下面是自己查阅资料,看了下一点源码的归纳所得,如果哪写错了欢迎指出!下面贴下小结图:
流程解析:Activity 调用 startActivity 后最后会调用 attach 方法,然后在 PolicyManager 实现一个 Ipolicy 接口,接着实现一个 Policy 对象,接着调用 makenewwindow(Context)方法,该方法会返回一个 PhoneWindow 对象,而 PhoneWindow 是 Window 的子类,在这个 PhoneWindow 中有一个 DecorView 的内部类,是所有应用窗口的根 View,即 View 的老大,直接控制 Activity 是否显示(引用老司机原话..),好吧,接着里面有一个 LinearLayout,里面又有两个 FrameLayout 他们分别拿来装 ActionBar 和 CustomView,而我们 setContentView()加载的布局就放到这个 CustomView 中!
总结下这三者的关系:打个牵强的比喻:我们可以把这三个类分别堪称:画家,画布,画笔画出的东西;画家通过画笔( LayoutInflater.infalte)画出图案,再绘制在画布(addView)上!最后显示出来(setContentView)
2.Activity,Task 和 Back Stack 的一些概念
接着我们来了解 Android 中 Activity 的管理机制,这就涉及到了两个名词:Task 和 Back Stack 了!
概念解析:
我们的 APP 一般都是由多个 Activity 构成的,而在 Android 中给我们提供了一个 Task(任务)的概念,就是将多个相关的 Activity 收集起来,然后进行 Activity 的跳转与返回!当然,这个 Task 只是一个 frameworker 层的概念,而在 Android 中实现了 Task 的数据结构就是 Back Stack(回退堆栈)!相信大家对于栈这种数据结构并不陌生,Java 中也有个 Stack 的集合类!栈具有如下特点:
后进先出(LIFO),常用操作入栈(push),出栈(pop),处于最顶部的叫栈顶,最底部叫栈底
而 Android 中的 Stack Stack 也具有上述特点,他是这样来管理 Activity 的:
当切换到新的 Activity,那么该 Activity 会被压入栈中,成为栈顶!而当用户点击 Back 键,栈顶的 Activity 出栈,紧随其后的 Activity 来到栈顶!
我们来看下官方文档给出的一个流程图:
流程解析:
应用程序中存在 A1,A2,A3 三个 activity,当用户在 Launcher 或 Home Screen 点击应用程序图标时,启动主 A1,接着 A1 开启 A2,A2 开启 A3,这时栈中有三个 Activity,并且这三个 Activity 默认在同一个任务(Task)中,当用户按返回时,弹出 A3,栈中只剩 A1 和 A2,再按返回键,弹出 A2,栈中只剩 A1,再继续按返回键,弹出 A1,任务被移除,即程序退出!
接着在官方文档中又看到了另外两个图,处于好奇,我又看了下解释,然后跟群里的人讨论了下:
然后还有这段解释:
然后总结下了结论:
3.Task 的管理
1)文档翻译:
好的,继续走文档,从文档中的 ManagingTasks 开始,大概的翻译如下:
如上面所述,Android 会将新成功启动的 Activity 添加到同一个 Task 中并且按照以"先进先出"方式管理多个 Task 和 Back Stack,用户就无需去担心 Activites 如何与 Task 任务进行交互又或者它们是如何存在于 Back Stack 中!或许,你想改变这种正常的管理方式。比如,你希望你的某个 Activity 能够在一个新的 Task 中进行管理;或者你只想对某个 Activity 进行实例化,又或者你想在用户离开任务时清理 Task 中除了根 Activity 所有 Activities。你可以做这些事或者更多,只需要通过修改 AndroidManifest.xml 中< activity >的相关属性值或者在代码中通过传递特殊标识的 Intent 给 startActivity( )就可以轻松的实现对 Actvitiy 的管理了。
< activity >中我们可以使用的属性如下:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
你能用的主要的 Intent 标志有:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_SINGLE_TOP
好的,接下来逐个介绍这些怎么用:
2)taskAffinity 和 allowTaskReparenting
默认情况下,一个应用程序中的所有 activity 都有一个 Affinity,这让它们属于同一个 Task。你可以理解为是否处于同一个 Task 的标志,然而,每个 Activity 可以通过< activity>中的 taskAffinity 属性设置单独的 Affinity。不同应用程序中的 Activity 可以共享同一个 Affinity,同一个应用程序中的不同 Activity 也可以设置成不同的 Affinity。Affinity 属性在 2 种情况下起作用:
3)launchMode:
四个可选值,启动模式我们研究的核心,下面再详细讲!他们分别是:standard(默认),singleTop,singleTask,singleInstance
4)清空栈
4.Activity 的四种加载模式详解:
接下来我们来详细地讲解下四种加载模式:他们分别是:standard(默认),singleTop,singleTask,singleInstance 在泡在网上的日子看到一篇图文并茂的讲解启动模式的,很赞,可能更容易理解吧,这里借鉴下:
原文链接:Activity启动模式图文详解:standard, singleTop, singleTask 以及 singleInstance
英文原文:Understand Android Activity's launchMode: standard, singleTop, singleTask and singleInstance
另外还有一篇详细讲解加载模式的:Android中Activity四种启动模式和taskAffinity属性详解
先来看看总结图:
模式详解:
standard 模式:
标准启动模式,也是 activity 的默认启动模式。在这种模式下启动的 activity 可以被多次实例化,即在同一个任务中可以存在多个 activity 的实例,每个实例都会处理一个 Intent 对象。如果 Activity A 的启动模式为 standard,并且 A 已经启动,在 A 中再次启动 Activity A,即调用 startActivity(new Intent(this,A.class)),会在 A 的上面再次启动一个 A 的实例,即当前的桟中的状态为 A-->A。
singleTop 模式:
如果一个以 singleTop 模式启动的 Activity 的实例已经存在于任务栈的栈顶,那么再启动这个 Activity 时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的 onNewIntent()方法将 Intent 对象传递到这个实例中。举例来说,如果 A 的启动模式为 singleTop,并且 A 的一个实例已经存在于栈顶中,那么再调用 startActivity(new Intent(this,A.class))启动 A 时,不会再次创建 A 的实例,而是重用原来的实例,并且调用原来实例的 onNewIntent()方法。这时任务栈中还是这有一个 A 的实例。如果以 singleTop 模式启动的 activity 的一个实例已经存在与任务栈中,但是不在栈顶,那么它的行为和 standard 模式相同,也会创建多个实例。
singleTask 模式:
只允许在系统中有一个 Activity 实例。如果系统中已经有了一个实例,持有这个实例的任务将移动到顶部,同时 intent 将被通过 onNewIntent()发送。如果没有,则会创建一个新的 Activity 并置放在合适的任务中。
官方文档中提到的一个问题:
singleInstance 模式
保证系统无论从哪个 Task 启动 Activity 都只会创建一个 Activity 实例,并将它加入新的 Task 栈顶也就是说被该实例启动的其他 activity 会自动运行于另一个 Task 中。当再次启动该 activity 的实例时,会重用已存在的任务和实例。并且会调用这个实例的 onNewIntent()方法,将 Intent 实例传递到该实例中。和 singleTask 相同,同一时刻在系统中只会存在一个这样的 Activity 实例。
5.Activity 拾遗
对于 Activity 可能有些东西还没讲到,这里预留一个位置,漏掉的都会在这里补上!首先是群友珠海-坤的建议,把开源中国的 Activity 管理类也贴上,嗯,这就贴上,大家可以直接用到项目中~
1)开源中国客户端 Activity 管理类:
本节小结:
好的,本节就到这里,东西都比较苦涩难懂,暂时知道下即可,总结下 Task 进行整体调度的相关操作吧:
按 Home 键,将之前的 Task 切换到后台
长按 Home 键,会显示出最近执行过的 Task 列表
在 Launcher 或 HomeScreen 点击 app 图标,开启一个新 Task,或者是将已有的 Task 调度到前台
启动 singleTask 模式的 Activity 时,会在系统中搜寻是否已经存在一个合适的 Task,若存在,则会将这个 Task 调度到前台以重用这个 Task。如果这个 Task 中已经存在一个要启动的 Activity 的实例,则清除这个实例之上的所有 Activity,将这个实例显示给用户。如果这个已存在的 Task 中不存在一个要启动的 Activity 的实例,则在这个 Task 的顶端启动一个实例。若这个 Task 不存在,则会启动一个新的 Task,在这个新的 Task 中启动这个 singleTask 模式的 Activity 的一个实例。
启动 singleInstance 的 Activity 时,会在系统中搜寻是否已经存在一个这个 Activity 的实例,如果存在,会将这个实例所在的 Task 调度到前台,重用这个 Activity 的实例(该 Task 中只有这一个 Activity),如果不存在,会开启一个新任务,并在这个新 Task 中启动这个 singleInstance 模式的 Activity 的一个实例。
好的本节就到这里,关于 Task 与 Activity 加载模式的东西还是比较复杂的,下面给大家贴下编写该文的时候的一些参考文献,可以自己看看~
参考文献:
版权声明: 本文为 InfoQ 作者【向阳逐梦】的原创文章。
原文链接:【http://xie.infoq.cn/article/867fbce3dabf7a2623e90c7bd】。文章转载请联系作者。
评论