activity启动模式 android,专题:详解Android组件Activity的启动模式singleTask_51CTO.COM
在Android应用程序中,可以配置Activity以四种方式来启动,其中最令人迷惑的就是"singleTask"这种方式了,官方文档称以这种方式启动的Activity总是属于一个任务的根Activity。果真如此吗?本文将为你解开Activity的"singleTask"之谜。在解开这个谜之前,我们先来简单了解一下在Android应用程序中,任务(Task)是个什么样的概念。我们知道,Activ
在Android应用程序中,可以配置Activity以四种方式来启动,其中最令人迷惑的就是"singleTask"这种方式了,官方文档称以这种方式启动的Activity总是属于一个任务的根Activity。果真如此吗?本文将为你解开Activity的"singleTask"之谜。
在解开这个谜之前,我们先来简单了解一下在Android应用程序中,任务(Task)是个什么样的概念。我们知道,Activity是 Android应用程序的基础组件之一,在应用程序运行时,每一个Activity代表一个用户操作。用户为了完成某个功能而执行的一系列操作就形成了一 个Activity序列,这个序列在Android应用程序中就称之为任务,它是从用户体验的角度出发,把一组相关的Activity组织在一起而抽象出 来的概念。
对初学者来说,在开发Android应用程序时,对任务的概念可能不是那么的直观,一般我们只关注如何实现应用程序中的每一个Activity。事实 上,Android系统中的任务更多的是体现是应用程序运行的时候,因此,它相对于Activity来说是动态存在的,这就是为什么我们在开发时对任务这 个概念不是那么直观的原因。不过,我们在开发Android应用程序时,还是可以配置Activity的任务属性的,即告诉系统,它是要在新的任务中启动 呢,还是在已有的任务中启动,亦或是其它的Activity能不能与它共享同一个任务,具体配置请参考官方文档:
首先在Android源代码工程中创建一个Android应用程序工程,名字就称为Task吧。
关于如何获得Android源代码工程,请参考在 Ubuntu上下载、编译和安装Android最新源代码一文;关于如何在Android源代码工程中创建应用程序工程,请参考在Ubuntu上为 Android系统内置Java应用程序测试Application Frameworks层的硬件服务一文。
这个应用程序工程定义了一个名为shy.luo.task的package,这个例子的源代码主要就是实现在这里 了。
下面,将会逐一介绍这个package里面的文件。
应用程序的默认Activity定义在src/shy/luo/task/MainActivity.java文件中。
它的实现很简单。
当点击它上面的一个按钮的时候,就会启动另外一个名字为“shy.luo.task.subactivity”的Actvity。
名字为“shy.luo.task.subactivity”的Actvity实现在src/shy/luo/task/SubActivity.java文件中:
注意,这里的SubActivity的launchMode属性配置为"singleTask"。
再来看界面配置文件。
它们定义在res/layout目录中,main.xml文件对应MainActivity的界面:
[html] view plaincopy
这样,原材料就准备好了,接下来就要编译了。
有关如何单独编译Android源代码工程的模块,以及如何打包system.img,
请参考如何单独编译Android源代码中的模块一文。
执行以下命令进行编译和打包:
现在,我们如何来确认SubActivity是不是在新的任务中启动并且位于这个新任务的堆栈底部呢?
Android源代码工程为我们准备了adb工具。
可以查看模拟器上系统运行的状况。
执行下面的命令查看:
首先是获得用来启动Activity的Intent的Flags,并且保存在launchFlags变量中。
这里,launcFlags的Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP位没有置位。
因此,notTop为null。
接下来的这个if语句:
这个函数无非就是根据即将要启动的SubActivity的taskAffinity属性值在系统中查找这样的一个Task:Task的affinity 属性值与即将要启动的Activity的taskAffinity属性值一致。
如果存在,就返回这个Task堆栈顶端的Activity回去。
在上面的 AndroidManifest.xml文件中,没有配置MainActivity和SubActivity的taskAffinity属性,于是它们的 taskAffinity属性值就默认为父标签application的taskAffinity属性值,这里,标签application的 taskAffinity也没有配置,于是它们就默认为包名,即"shy.luo.task"。
由于在启动SubActivity之 前,MainActivity已经启动,MainActivity启动的时候,会在一个新的任务里面启动,而这个新的任务的affinity属性就等于它 的第一个Activity的taskAffinity属性值。
这个函数中作用无非就是找到ID等于参数taskId的任务,然后在这个任务中查找是否已经存在即将要启动的Activity的实例。
如果存在,就会把这 个Actvity实例上面直到任务堆栈顶端的Activity通过调用finishActivityLocked函数将它们结束掉。
在这个例子中,就是要 在属性值affinity等于"shy.luo.task"的任务中看看是否存在SubActivity类型的实例,如果有,就把它上面的 Activity都结束掉。
这里,属性值affinity等于"shy.luo.task"的任务只有一个MainActivity,而且它不是 SubActivity的实例,所以这个函数就返回null了。
它是例行性地检查当前任务顶端的Activity,
是否是即将启动的Activity的实例,
如果是否的话,在某些情况下,它什么也不做,就结束这个函数调用了。
这里,当前任务顶端的Activity为MainActivity,它不是SubActivity实例,于是继续往下执行:
到这里,思路就理清了。
虽然SubActivity的launchMode被设置为"singleTask"模式,但是它并不像官方文档描述的一样:
The system creates a new task and instantiates the activity at the root of the new task.
而是在跟它有相同taskAffinity的任务中启动,并且位于这个任务的堆栈顶端,
注意,这里我们设置MainActivity的taskAffinity属性值为"shy.luo.task.main.activity",
设置 SubActivity的taskAffinity属性值为"shy.luo.task.sub.activity"。
重新编译一下程序,在模拟器上把这 个应用程序再次跑起来,
用“adb shell dumpsys activity”命令再来查看一下系统运行的的任务,就会看到:
更多推荐
所有评论(0)