Activity和Task
从一个BroadcastReceiver的onReceive方法启动一个Activity通常需要在Intent里边添加一个Flag Intent.FLAG_ACTIVITY_NEW_TASK
看文档:
If set, this activity will become the start of a new task on this history stack. A task (from the activity that started it to the next task activity) defines an atomic group of activities that the user can move to. Tasks can be moved to the foreground and background; all of the activities inside of a particular task always remain in the same order. See Application Fundamentals: Activities and Tasks for more details on tasks.
This flag is generally used by activities that want to present a "launcher" style behavior: they give the user a list of separate things that can be done, which otherwise run completely independently of the activity launching them.
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 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,新启动的Activity将会放置到一个新的Task中。看这句
“This flag is generally used by activities that want to present a "launcher" style behavior: they give the user a list of separate things that can be done, which otherwise run completely independently of the activity launching them. ” 说的是这个Flag通常用在类似于"launcher" 的行为上,也就是说使用了这个Flag就相当于启动了一个新的应用程序。
如果仅仅是加上这样一个Flag,那么就有问题了,像我这样操作:
1.用Activity1 发一个广播给Receiver
2.在Receiver的onReceive里边启动Activity2,Intent里边必须加上Intent.FLAG_ACTIVITY_NEW_TASK ,否则运行会出问题。
3.Activity2打开后,按Back键。
4.长按Home键,重新进去程序。
当你操作到3的时候,你会发现已经出问题了:按Back没有回到Activity1,而是直接退出了!这难道不奇怪吗?
当你操作到4的时候,也有问题:程序不是从Activity1启动,而是直接进入Activity2!
So Strange!!
So Strange??
NO!
现在该讲讲Task了,Task是什么,说白了就是Activity的容器,你可以把Activity1,Activity2,Activity3放到一个Task里,把ActivityA,ActivityB,ActivityC放到另一个Task里,任何一个Activity都会有一个他所属于的Task。
Activity有四种启动模式:
1.standard(默认模式)
2.singleTop
3.singleTask
4.singleInstance
如果不对Activity的启动进行设置,Activity默认以standard模式启动,这四种启动模式可以分为两组,{standard singleTop}是一组,这种启动模式的Activity都可以有多个实例,{singleTask singleInstance}是一组,这种启动模式的Activity只有一个实例。
为了清除的说明Activity与Task的关系,我们来做实验:
(………………………实验1)
包名:"com.hou.activitytest"
三个Activity:Activity1,Activity2,Activity3
(1启动2,2启动3)
关键看AndroidManifest.xml文件:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hou.activitytest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="4" /> <application android:icon="@drawable/icon" android:label="@string/app_name" > <activity android:name=".Activity1" android:alwaysRetainTaskState="true" android:icon="@drawable/btn_green" android:label="@string/app_name" android:launchMode="singleTask" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Activity2" android:taskAffinity="com.hou.activitytest2" android:icon="@drawable/btn_red" android:launchMode="singleTask" > </activity> <activity android:name=".Activity3" android:taskAffinity="com.hou.activitytest2" android:icon="@drawable/icon" android:launchMode="singleTask" > </activity> </application> </manifest>
先跑起来再说:结果很正常Activity1启动了Activity2,Activity2启动Activity3,按返回键也能按照顺序返回。
等你连续按返回键退出后,长按Home键,奇怪的现象出现了:
这个应用竟然有两个图标!!!不信?有图有真相
震惊了吧!现在反过来看看代码,Activity的代码没什么特别,就是几个跳转页面的代码。关键在于AndroidManifest.xml文件,有几点要注意
1.三个Activity的启动模式都是 "singleTask"
2.Activity2和Activity3有个android:taskAffinity="com.hou.activitytest2"属性
3.三个Activity分别设置了不同的图标
现在我来解释一下,还是通过实验,
(………………………实验2)
现在把Activity2和Activity3的
android:taskAffinity="com.hou.activitytest2"属性删除,重新运行。启动后连续跳转然后连续返回,没有异常,长按Home键,只有一个绿色图标。
(………………………实验3)
我们再把android:launchMode="singleTask" 全部去掉,重新实验,发现结果和上次一样。
如此看来android:launchMode="singleTask" 对连个图标的产生没有起任何作用,起作用的是android:taskAffinity="com.hou.activitytest2"
可能有人要问了,为什么taskAffinity="com.hou.activitytest2"呢,包名是="com.hou.activitytest"啊 ,没错,我只故意这样弄来与包名区分的,
(………………………实验4)
那好现在把android:taskAffinity="com.hou.activitytest2"都改为
android:taskAffinity="com.hou.activitytest"添加到Activity2和Activity3
重新运行,结果还是跟上次一样。
为什么会有上述结果,首先我们要知道taskAffinity是干嘛的,查下资料发现taskAffinity是用来标志Activity归属于哪一个Task,具有相同taskAffinity的Activity属于同一个Task。看来第一个实验中我们的程序中有两个Task,所以就会有两个图标,第2 3 4 个实验中都只有一个Task,所以只有一个图标。
为什么实验2设置android:launchMode="singleTask" 没有起作用呢?按说Activity2和Activity3都是singleTask启动的,应该有三个Task,也就是有三个图标才对啊。因为如果你不对Activity设置taskAffinity属性,那么默认该属性的值为应用的包名,也就是实验2中三个Activity的taskAffinity属性都是相同的。也是这三个Activity是属于同一个Task的,singleTask也就失效了。如果想让singleTask起作用,把taskAffinity的属性换成跟默认的包名不一样就行了。
这也就是为什么实验1中为什么,会有两个图标,而不是三个,应为Activity2和Activity3的taskAffinity属性是一样的。
你把Activity3的taskAffinity设置为android:taskAffinity="com.hou.activitytest3"试一下,怎么样,三个图标出现了吧!
说的很乱,先在总结一下:
1.如果你想以singleTask启动一个Activity,就要给这个Activity设置与包名不同的android:taskAffinity 属性。
2.在用户看来,一个Task就是一个应用(至少功能可以独立出来)
关于Task与图标的规律是:
1.属于不同Task有相同taskAffinity属性的一组Activity对应一个icon
2.属于不同Task,taskAffinity属性也不相同的Activity各自有一个icon
3.属于相同Task的一组Activity有一个icon
4.多个Activity对应一个icon的情况,icon使用的是按照AndroidManifest文件中Activity书写顺序的最后一个Activity设置的icon(如果没有,取他前一个,直到application标签里的icon,如果application也没有icon,用系统默认的)
补充一下singleTask和singleInstance的区别:
singleInstance启动的Activity独占一个Task,启动它的Activity和它所启动的Activity跟它的TaskID肯定不一样。
singleTask启动的Activity会根据它的taskAffinity属性来判断是否自己新建立一个Task,如果根据taskAffinity属性找到了它所属于的Task就不用新建Task了,否则就要新建,并且它位于Task的栈底。
如果你想把ActivityM ActivityN 和ActivityQ放到同一个Task中,你只需要把ActivityM (在Task栈底)的launchMode设置为android:launchMode="singleTask"
taskAffinity属性设置为一个跟包名不一致的,比如
android:taskAffinity="com.test.myTask"
ActivityN 和ActivityQ 的launchMode设置为singleTask或standard都可以,taskAffinity必须也设置为android:taskAffinity="com.test.myTask"
如果一个Activity的launchMode是standard或singleTop,那么谁启动它,它就和谁在一个相同的Task里。
=========写的太乱了===========