关闭

按下Home键后重新返回程序,显示最后的Activity

标签: android代码bug解决
1788人阅读 评论(0) 收藏 举报
分类:
问题描述在一个android应用程序中,如果有两个activity:A,B,其中A是主界面,B是由A跳转所得.那么当我们在B界面按下Home键时会返回桌面,这时无论是长按Home键调出最近访问程序,还是从菜单再进入一遍程序,我们都期望...

问题描述

在一个android应用程序中,如果有两个activity:A,B,其中A是主界面,B是由A跳转所得.那么当我们在B界面按下Home键时会返回桌面,这时无论是长按Home键调出最近访问程序,还是从菜单再进入一遍程序,我们都期望能直接返回到B界面,但是有的时候我们却无法如愿而又找不出问题的所在,这篇笔记记录下了部分可能存在的情况,以及原理。

Activity的Launch Mode


四种模式中的standard(默认)和singletop模式很好理解。

对于singletask,上文作者也给出了详细的总结,即一个task栈中只能有一个实例,这个activity实例有可能在原来的任务栈中存在,那么再次调用时就会把它上面的所有activity对象清空,保证自己显示出来。这条非常重要。

对于singleInstance,会为activity新开辟出一个task栈,对于到底两个栈如何互相转换,上文中也已谈及。

详细的测试实例可以参考:http://mypyg.iteye.com/blog/919643

另:singleInstance的详细解释(来自:http://marshal.easymorse.com/archives/2950):

解释singleInstance模式比较麻烦。
首先要说一下Task(任务)的概念。
如果是Swing或者Windows程序,可能有多个窗口可以切换,但是你无法在自己程序中复用人家的窗口。注意是直接复用人家的二进制代码,不是你拿到人家api后的源代码级调用。
Android可以做到,让别人的程序直接复用你的Activity(类似桌面程序的窗口)。
Android为提供这种机制,就引入了Task的概念。Task可以认为是一个栈,可放入多个Activity。比如启动一个应用,那么Android就创建了一个Task,然后启动这个应用的入口Activity,就是intent-filter中配置为main和launch的那个(见一个APK文件部署产生多个应用安装的效果)。这个Activity是根(Root)Activity,可能会在它的界面调用其他Activity,这些Activity如果按照上面那三个模式,也会在这个栈(Task)中,只是实例化的策略不同而已。


验证的办法是调用和打印Activity的taskId:

"task id: "+this.getTaskId()

会发现,无论切换Activity,taskId是相同的。

当然也可以在这个单一的Task栈中,放入别人的Activity,比如google地图,这样用户看过地图按回退键的时候,会退栈回到调用地图的Activity。对用户来说,并不觉得在操作多个应用。这就是Task的作用。

但是,有这样的需求,多个Task共享一个Activity(singleTask是在一个task中共享一个Activity)。

现成的例子是google地图。比如我有一个应用是导游方面的,其中调用的google地图Activity。那么现在我比如按home键,然后到应用列表中打开google地图,你会发现显示的就是刚才的地图,实际上是同一个Activity。

如果使用上面三种模式,是无法实现这个需求的。google地图应用中有多个上下文Activity,比如路线查询等的,导游应用也有一些上下文Activity。在各自应用中回退要回退到各自的上下文Activity中。

singleInstance模式解决了这个问题。让这个模式下的Activity单独在一个task栈中。这个栈只有一个Activity。导游应用和google地图应用发送的intent都由这个Activity接收和展示。

这里又有两个问题:

如果是这种情况,多个task栈也可以看作一个应用。比如导游应用启动地图Activity,实际上是在导游应用task栈之上singleInstance模式创建的(如果没有的话就新建,如果有就是直接显示它)一个新栈,当这个栈里面的唯一Activity,地图Activity回退的时候,只是把这个栈移开了,这样就看到导游应用刚才的Activity了;
多个应用(Task)共享一个Activity要求这些应用都没有退出,比如刚才强调要用home键从导游应用切换到地图应用。因为,如果退出导游应用,而这时也地图应用并未运行的话,那个单独的地图Activity(task)也会退出了。


Intent的常用FLAG参数

Intent.FLAG_ACTIVITY_NEW_TASK
默认的跳转类型,会重新创建一个新的Activity,不过与这种情况,比方说Task1中有A,B,C三个Activity,此时在C中启动D的话,如果在Manifest.xml文件中给D添加了Affinity的值和Task中的不一样的话,则会在新标记的Affinity所存在的Task中压入这个Activity。如果是默认的或者指定的Affinity和Task一样的话,就和标准模式一样了启动一个新的Activity.
FLAG_ACTIVITY_SINGLE_TOP
这个FLAG就相当于加载模式中的singletop,比如说原来栈中情况是A,B,C,D在D中启动D,栈中的情况还是A,B,C,D

FLAG_ACTIVITY_CLEAR_TOP
这个FLAG就相当于加载模式中的SingleTask,这种FLAG启动的Activity会把要启动的Activity之上的Activity全部弹出栈空间。类如:原来栈中的情况是A,B,C,D这个时候从D中跳转到B,这个时候栈中的情况就是A,B了

FLAG_ACTIVITY_BROUGHT_TO_FRONT
这个网上很多人是这样写的。如果activity在task存在,拿到最顶端,不会启动新的Activity。这个有可能会误导大家! 他这个FLAG其实是这个意思! 比方说我现在有A,在A中启动B,此时在A中Intent中加上这个标记。此时B就是以 FLAG_ACTIVITY_BROUGHT_TO_FRONT 这个启动的,此时在B中再启动C,D(正常启动C,D),如果这个时候在D中再启动B,这个时候最后的栈的情况是 A,C,D,B. 特别注意的是,我上面说的网上人描述的这个FLAG,会很容易让人误解成这样,A,B,C,D都是标准加载,然后我在D中启动A,这个intent加上FLAG_ACTIVITY_BROUGHT_TO_FRONT ,就会误认为变成B,C,D,A!!其实不是,这个时候应该是A,B,C,D,A.不信的人大家试试看。不过下面这个标记和这个标记就会让大家明白了!

FLAG_ACTIVITY_REORDER_TO_FRONT
就按在 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT 最后说的,如果在A,B,C,D正常启动的话,不管B有没有用FLAG_ACTIVITY_BROUGHT_TO_FRONT启动,此时在D中启动B的话,还是会变成A,C,D,B的。

FLAG_ACTIVITY_NO_USER_ACTION
onUserLeaveHint()作为activity周期的一部分,它在activity因为用户要跳转到别的activity而要退到background时使用。
比如,在用户按下Home键(用户的choice),它将被调用。比如有电话进来(不属于用户的choice),它就不会被调用。
那么系统如何区分让当前activity退到background时使用是用户的choice?
它是根据促使当前activity退到background的那个新启动的Activity的Intent里是否有     FLAG_ACTIVITY_NO_USER_ACTION来确定的。
注意:通过调用finish()使该activity销毁时不会调用该函数

FLAG_ACTIVITY_NO_HISTORY
用这个标记顾名思义! 意思就是说用这个FLAG启动的Activity,一旦推出,他就不会存在于栈中,比方说!原来是A,B,C 这个时候再C中以这个FLAG启动D的 , D再启动E,这个时候栈中情况为A,B,C,E。

总结:

如果需要自己在按下Home键后还能从最近打开的程序中恢复回离开时的Activity,那么一定要注意自己最后的Activity是否存在task栈的最顶端。

例如:只要该栈中之前的任何一个Activity在manifest文件中定义了启动模式为singleTask,那么只要再次返回程序,一定会回到该Activity上,而它之上的Activity都被销毁了。

(转发请注明转自:学PHP
1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:18435次
    • 积分:191
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:12篇
    • 译文:0篇
    • 评论:0条
    文章分类