按以前的认识, Android的APP运行到哪个页面,按Home返回,再点击桌面图标,程序应该回到刚才显示的界面才对。可是出现了一个bug,客户的手机上,按Home键再返回,程序会重新开始运行,而不是回到刚才的界面。这让我很头疼。。。。
首先要搞清楚点击桌面图标,到底程序是怎么打开的。先看关键源码
- void startActivitySafely(Intent intent, Object tag) {
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException e) {
- ......
- } catch (SecurityException e) {
- ......
- }
- }
这里intent包含的信息为:action = "android.intent.action.Main",category="android.intent.category.LAUNCHER"
程序启动中加了个 Intent.FLAG_ACTIVITY_NEW_TASK的属性,在这里有些人对改Flag的认识有误差,以为有这个Flag的就会重新启动一个Task来存放Activity实例。对该Flag的研究,详情见 http://www.cnblogs.com/xiaoQLu/archive/2012/07/17/2595294.html
关键点是:FLAG_ACTIVITY_NEW_TASK: 设置此状态,记住以下原则,首先会查找是否存在和被启动的Activity具有相同的亲和性的任务栈(即taskAffinity,注意同一个应用程序中的activity的亲和性一样,所以下面的a情况会在同一个栈中,前面这句话有点拗口,请多读几遍),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变,如果没有,则新建一个栈来存放被启动的activity。
那么LauncherMode对按Home键再点击图标有什么影响呢。
我们来做个试验, LauncherMode为standard, singleTop, singleTask都再同一个栈里面的,就没什么好试的了,SingleInstance比较特别,
程序入口ActivityA不设置LauncherMode, ActivityB设为SingleInstance,ActivityC不设置LauncherMode。
试验1:ActivityA->ActivityB->Home键->点击桌面图标。
结果启动了ActivityA, 结论:点击图标程序会启动属于该运用的主Task,即程序第一个启动页面所在的Task, 因为ActivityB不在主Task中,所以系统启动主Task栈顶的ActivityA。
试验2:ActivityA->ActivityB->ActivityC->Home键->点击桌面图标
结果启动了ActivityC,结论同上。
试验3:ActivityA->ActivityB->ActivityC->返回键->返回键
结果第一次返回到了ActivityA,再按返回键回到ActivityB。结论,按返回键实际上是对Task中实例的出栈操作,程序先弹出当前Activity所在栈的所有实例,再去弹出其他栈的实例。
在这里说一些android:allowTaskReparenting=""属性,设置该属性,表示允许其他Task暂时无视该Activity的taskAffinity对栈的影响,可以把该Activity压入自己的栈中。等到该Activity原来的task启动了,改Activity立马根据taskAffinity回到自己的Task中。
例:在"TaskOne应用"中有一个天气预报Activity A, Activity A与"TaskOne应用"中的其它Activity有默认的关系
(taskAffinity属性都没有设置), 并且allowTaskReparenting属性设置为true, 现在存在一个"TaskTwo应用
"启动了"TaskOne应用"中的天气预报Activity A, 这时Activity A与"TaskTwo应用"中的Activity在同一个Task,
命名这个Task堆栈为TaskA, 这时"TaskOne应用"启动, 并且又打开发天气预报Activity A, 这时Activity A会从TaskA堆栈中转移到
"TaskOne应用"所在的堆栈, 即Activity A可以在多个堆栈中来回转移.
详情见http://blog.csdn.net/koko7958/article/details/8082367
http://www.cnblogs.com/xiaoQLu/archive/2012/07/17/2595294.html
一个新的activity,默认情况下,被加载进调用startActivity()方法的activity对象所在的那个任务中。它被压入和调用者所在的同一个栈中
taskaffinity和Intent.FLAG_ACTIVITY_NEW_TASK或者taskAffinity和SingleTask一起用会开启一个新的Task来存放activity实例,而SingleTask和Intent_FLAG_ACTIVITY_NEW_TASK一起用并不会开启一个新的Task,所以我猜想singleTask模式启动的activity也是有设置Intent.FLAG_ACTIVITY_NEW_TASK属性的。单独使用taskaffinity属性并不会开启一个新的Task。
FLAG_ACTIVITY_CLEAR_TOP也要慎用
public static final int FLAG_ACTIVITY_CLEAR_TOP
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.