从浏览器打开一个本地应用的回退栈问题

来源:互联网 发布:用python编写数据库 编辑:程序博客网 时间:2024/05/22 08:22

1、首先,先理一下回退栈的问题。

开机启动后,HomeLauncher)所在的Activity在整个回退栈的栈底。


Launcher上的图标点击进入一个应用(Activity)时,默认在启动整个ActivityIntentflag里面加入了FLAG_ACTIVITY_NEW_TASK标记(这个标记的作用是:首先会查找是否存在和被启动的Activity具有相同的亲和性的任务栈,如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变,如果没有,则新建一个栈来存放被启动的activity)。也就是说从launcher启动的Activity默认会在一个新的Task里面。比如我们启动了一个应用,ABC三个Activity是同一个应用(ABC没有设置亲和性,默认都是跟随启动它的那个activity的亲和性的),都归为Task2

如果此时在C里面打开另一个应用另起一个Task

如果,此时按下了Home键,那么Task1将会移动到回退栈的栈顶

 Home里面点击A,那么Task2将会移动到栈顶,回退的时候就是C->B->A->Home


2、应用场景:

A 应用打开一个浏览器,浏览器里面有个链接打开本地应用B(B有两个界面B.1主界面和B.2次界面)。

默认情况下,跳转的activity都在一个Task里面,实际情况是A在Task2(从home为Task1开始)、浏览器(Task3,从A中启动浏览器,浏览器的主页面应该是singleTask模式,所以会在新的task中启动浏览器)、B(B中有两个activity均是标准模式,从B.1启动了B.2)未设置flag标记时与浏览器在同一个Task3中,此时我们从B.2按返回键,则会经过B->浏览器->A;

如果从浏览器中启动B.1,在B.1界面(该B.1界面的affinity跟随启动它的浏览器),按Home键,然后在从桌面点击B应用图标进入B.1界面(此时从launcher进入一个应用会默认给intent加上NEW_TASK 这个flag标记,那么新启动的这个B.1就在一个新的Task4中(该activity的affinity属于B所在的应用),也就是在目前的回退栈中存在两个B.1实例。此时,从B.1按返回键,则直接返回到桌面(在Task4中的B.1实例销毁,Task也跟着消亡。

然后我们从launcher里面点击浏览器图标,显示的就是B.1界面。而此时从B.1返回,就返回到浏览器再返回就到桌面了(说明从其他应用启动一个浏览器,浏览器本身做了启动模式处理即不会跟其他应用在一个Task中)

理论上是如上面的情况,但是目前在我的手机的浏览器中打开B.1,按home键后,在点击浏览器,实际上只显示了浏览器的界面,而B.1界面被销毁了,之所以销毁了猜想是因为浏览器主界面是singleTask模式,必然会pop掉在其上面的B.1界面。为了验证这个猜想,我在B.1界面打印了taskID:
07-27 14:46:44.806 29463-29463/com.tongxt.browserapp E/MainActivity: onCreate:taskid = 8307-27 14:46:44.845 29463-29463/com.tongxt.browserapp I/MainActivity: onStart07-27 14:46:44.845 29463-29463/com.tongxt.browserapp E/MainActivity: onResume
这里的MainActivity就当做是B.1界面,上面的log是从桌面图标进入B所在的应用的,其taskid为83,进入后的界面如下:
点击按钮,进入second界面(及B.2界面)
07-27 14:51:46.939 29463-29463/com.tongxt.browserapp E/SecondActivity: onCreate:taskid = 83
B.2的taskid也是83,说明这两个activity是在同个栈中的。
此时,我从浏览器的快捷方式中去启动B.1界面:
07-27 14:55:08.259 29463-29463/com.tongxt.browserapp E/MainActivity: onCreate:taskid = 6007-27 14:55:08.314 29463-29463/com.tongxt.browserapp I/MainActivity: onStart07-27 14:55:08.314 29463-29463/com.tongxt.browserapp E/MainActivity: onResume
B.1的taskid变成了60,使用adb shell dumpsys activity查看栈信息
TaskRecord{42d480b8 #60 A com.baidu.browser.apps U 0}    Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10600000 cmp=com.baidu.browser.apps/com.baidu.browser.framework.BdBrowserActivity }      Hist #7: ActivityRecord{426d3ec8 com.tongxt.browserapp/.MainActivity}        Intent { act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=znn://aa.bb:80/test?p=12&d=1 cmp=com.tongxt.browserapp/.MainActivity }        ProcessRecord{42952048 29463:com.tongxt.browserapp/u0a62}
看有一个MainActivity(也就是B.1)是在百度浏览器的栈里面的。另外任务为83的栈中,也有一个B.1实例,和一个B.1启动的B.2实例
TaskRecord{4276a360 #83 A com.tongxt.browserapp U 0}    Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.tongxt.browserapp/.MainActivity }      Hist #4: ActivityRecord{426cc298 com.tongxt.browserapp/.SecondActivity}        Intent { cmp=com.tongxt.browserapp/.SecondActivity }        ProcessRecord{42952048 29463:com.tongxt.browserapp/u0a62}      Hist #3: ActivityRecord{426d4508 com.tongxt.browserapp/.MainActivity}        Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.tongxt.browserapp/.MainActivity bnds=[20,359][190,589] }        ProcessRecord{42952048 29463:com.tongxt.browserapp/u0a62}

接着,我按home键回到桌面,在点击浏览器图标,直接进入了浏览器界面,同时日志中显示了B.1的onDestory方法,说明浏览器确实是singleTask模式的。
07-27 15:03:30.119 29463-29463/com.tongxt.browserapp E/MainActivity: onDestroy


以上是一般情况下打开应用的一个回退栈实例。


如果我们把B.1的启动模式设置为singleTask,那么浏览器启动的B.1就和浏览器是不同的Task了。这时候按home键,在进入B.1会复用之前Task里面的实例。


另外一个应用场景:

在B应用已经启动并且当前在B.1界面(主界面),按home键回到桌面,再从浏览器中点击进入B应用的二级界面B.2,默认情况下按返回键会返回到浏览器界面,如何返回到B.1界面呢?

我们在B.2界面的activity属性设置为:

android:allowTaskReparenting="true"android:launchMode="singleTask"

前一个表示会把当前启动的activity移动到具有相同affinity的task中,也就是说如果B.1从桌面启动了,那么B.1默认在一个task中,此时别的应用或task启动了B.2,那么系统会把B.2移动到B.1所在的task中。

所以如果我们在浏览器里面启动了B.2,在B.2中返回键,就会返回到B.1中(前提是B.1已经启动过),再返回(此时B.2和B.1都销毁了,那么其task也跟着销毁了)就返回到浏览器task中。如果我们在B.2中按home键,然后再点击B应用的图标,那么呈现出来的就是B.2在最前面,返回进入B.1,在返回进入桌面。


如果是B.1未启动的情况下,从浏览器启动B.2,那么从B.2返回键返回到浏览器,如果从B.2按home键,再从桌面点击B应用图标,会直接进入B.2界面,再返回直接回到桌面。这种情况下B.1就不会显示了。原因是:从launcher打开一个应用,会去判断该应用是否已经启动过(也就是有了task),如果存在就直接把该task移动到最前面,而此时我们B应用的task里面只有B.2这个activity,所以也就只显示了它了。

以上情况都是基于B.1是standard启动模式的。如果换成singleTask模式,那么在B.1已经存在的情况下,从浏览器启动B.2(这时候的task是B.1在B.2的下面),home键回到桌面,再从launcher点击启动B.1的时候,必然会导致B.2被销毁(只能看到B.1界面),原因是该模式启动的activity会在原来的task里面查找是否已经有这个实例,存在的话,就会把这个实例之上的其他activity都pop掉。而如果B.1没有启动的话,从launcher点击进入B应用,首先会看到B.1界面,按返回键会进入B.2界面,再返回就到桌面了。

阅读全文
0 0