Android任务和返回栈(Tasks and Back Stack)

来源:互联网 发布:淘宝网中学生羊毛衫 编辑:程序博客网 时间:2024/05/27 00:40

        官方文档地址:http://developer.android.com/guide/components/tasks-and-back-stack.html

        一个应用程序通常包含多个Activity,每个Activity被设计用来让用户执行特定的action,并且能够启动其它的Activity。比如,一个邮件应用中可能会包含一个用于展示邮件列表的Activity,而当用户点击了其中某一封邮件的时候,就会打开另外一个Activity来显示该封邮件的具体内容。
        一个Activity甚至能启动设备中其它应用程序中的Activity。比如,如果你的应用希望去发送一封邮件,你就可以定义一个Intent去执行发送action,并且传入一些数据,如对方邮箱地址、邮件内容等。其它应用程序中的一个声明自己可以响应这种Intent的Activity随即就会被打开。在这种情景下,这个Intent是为了要发送邮件的,所以说邮件应用程序当中的“compose”Activity就被打开了(如果有多个Activity支持相同的Intent,那么系统会让用户选择一个使用)。当邮件发送出去之后,你的应用程序会继续,看起来就像刚才那个编写邮件的Activity就是你的应用程序中的一部分一样。即便多个Activity可能来自于不同的应用程序,Android也可以通过保持这些Activity在相同的任务(Task)中来保证无缝的用户体验。

        一个任务是用户要执行某些工作时要交互的Activity的集合,这些Activity被组织在一个栈(Stack)中,这个栈又被称为返回栈(the back stack),栈中Activity的顺序就是按照它们被打开的顺序依次存放的。
        手机的Home界面是大多数任务开始的地方,当用户在Home界面上点击了一个应用的图标时(或Home界面的一个快捷方式时),这个应用的任务就会被转移到前台。如果这个应用目前并没有任何一个任务的话(说明这个应用最近没有被启动过),系统就会去创建一个新的任务,该应用的主Activity将作为栈的根Activity(root activity)打开。

        当当前Activity启动了另外一个Activity的时候,新的Activity就会被放置到返回栈的栈顶并将获得焦点。前一个Activity仍然保留在返回栈当中,但会处于停止状态。当一个Activity停止时,系统会保留它的用户界面的当前状态。当用户按下Back键的时候,当前Activity被从栈顶弹出(该Activity被销毁),前一个Activity将继续(其之前的UI状态将被恢复)。返回栈中Activity的顺序永远不会改变,只能被压入(pushed)、被弹出(popped)——被当前Activity启动时被压入,当用户按返回键离开它时被弹出。因此,返回栈是一个典型的后进先出(last in, first out)的数据结构。下图通过时间轴的方式展示了多个Activity在返回栈当中的状态变化:


       如果用户继续按Back键,返回栈中的Activity会一个个地被弹出并露出前一个,直到最终返回到Home界面(或者返回到该任务开始时正在运行的那个Activity)。当返回栈中所有的Activity都被弹出时,任务就不存在了。

        刚看到老郭前几个月翻译了,翻译的也不错,我就不继续翻译了,参见:Android任务和返回栈完全解析,细数那些你所不知道的细节。本来正在详细地看英文文档,顺便翻译一下,严格按照原文翻译。老郭翻译时做了自己的加工,我这个强迫症只能去看英文文档了。

Activity的亲和性(taskAffinity):

affinity用于指定一个Activity更加愿意依附于哪一个task。默认情况下,同一个应用程序中的所有Activity都具有相同的taskAffinity,就是程序的包名。

Activity的allowTaskReparenting:

表明该Activity可以转移到具有相同affinity的task中。

Activity的alwaysRetainTaskState:

设置为true时,来保证任务在后台太久后,Task最底层之上的Activity不会被清理掉。

Activity的clearTaskOnLaunch:

设置为true时,只要用户离开当前任务,在返回时,最底层之上的所有Activity都会被清理掉。

Activity的finishOnTaskLaunch:

设置为true时,只要用户离开当前任务,在返回时,该Activity会被清理掉。

Activity的启动模式(launchMode):

standard:默认的启动模式。这种启动模式表示每次启动该Activity时系统都会为其创建一个新的实例,并且总会把它放入到当前的任务当中。声明成这种启动模式的Activity可以被实例化多次,一个任务当中也可以包含多个这种Activity的实例。

singleTop:如果要启动的Activity实例已经当前task的栈顶,系统不会重新创建Activity的实例,而是调用它的onNewIntent()方法把intent传给它。


singleTask:先在系统中查找属性值affinity等于它的taskAffinity的任务是否存在,如果存在这样的任务,它就会在这个任务中启动,直接调用它的onNewIntent()方法把intent传给它,而且它会在已有的任务中查看是否已经存在相应的Activity实例,如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity实例会位于任务的堆栈顶端中。否则不存在这样affinity的任务,就为它创建一个新的task,实例化该Activity并把它放入新task的根。

singleInstance:系统不会向保持该Activity实例的task中添加任何其它Activity,这个Activity实例始终是它所在task中的唯一成员,它所启动的其它Activity都将在别的task中打开。也就是说:singleInstance的Activity所在的Task不允许存在其他Activity,任何从该Activity加载的其它Actiivty(假设为Activity2)都会被放入其它的Task中,如果存在与Activity2相同affinity的Task,则在该Task内创建Activity2。如果不存在,则重新生成新的Task并入栈。

Intent的flag:

在调用startActivity()方法的时候,可以为Intent加入一个flag来改变Activity与任务的关联方式。

FLAG_ACTIVITY_NEW_TASK:

新启动的其它应用的Activity就会被放置到一个新的任务当中。这个flag的作用通常是模拟一种Launcher的行为,即列出一推可以启动的东西,但启动的每一个Activity都是在运行在自己独立的任务当中的。

FLAG_ACTIVITY_SINGLE_TOP:

如果要启动的Activity在当前任务中已经存在了,并且还处于栈顶的位置,那么就不会再次创建这个Activity的实例,而是直接调用它的onNewIntent()方法把intent传给它。这种flag和在launchMode中指定"singleTop"模式所实现的效果是一样的。

FLAG_ACTIVITY_CLEAR_TOP:

如果要启动的Activity在当前任务中已经存在了,就不会再次创建这个Activity的实例,而是会把这个Activity之上的所有Activity全部清理掉。比如说,一个任务当中有A、B、C、D四个Activity,然后D调用了startActivity()方法来启动B,并将flag指定成FLAG_ACTIVITY_CLEAR_TOP,那么此时C和D就会被关闭掉,现在返回栈中就只剩下A和B了。
那么此时Activity B会接收到这个启动它的Intent,你可以决定是让Activity B调用onNewIntent()方法(不会创建新的实例),还是将Activity B销毁掉并重新创建实例。如果Activity B没有在manifest中指定任何启动模式(也就是默认的"standard"模式),并且Intent中也没有加入一个FLAG_ACTIVITY_SINGLE_TOP,那么此时Activity B就会销毁掉,然后重新创建实例。而如果Activity B在manifest中指定了任何一种启动模式,或者是在Intent中加入了一个FLAG_ACTIVITY_SINGLE_TOP,那么就会调用Activity B的onNewIntent()方法。

FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK结合在一起使用也会有比较好的效果,比如可以将一个后台运行的任务切换到前台,并把目标Activity之上的其它Activity全部关闭掉。这个功能在某些情况下非常有用,比如说从通知栏启动Activity的时候。

        不管Activity是在一个新任务当中启动,还是在当前任务中启动,返回键永远都会把我们带回到之前的一个Activity中,这就是用户体验。但是有一种情况是比较特殊的,就是如果Activity指定了启动模式是"singleTask",并且启动的是另外一个应用程序中的Activity,这个时候当发现该Activity正好处于一个后台任务当中的话,就会直接将这整个后台任务一起切换到前台。此时按下返回键会优先将目前最前台的任务(刚刚从后台切换到最前台)进行回退,而不会直接回到原来task中来的那个Activity。

        最近使用百度云推送的SDK时,碰到了些问题,所以认认真真地看了一下任务和返回栈。记得当时做过一个笔试题,就问Activity的4种启动模式,我每个就一句话解释(当时只是了解,没有深入研究过),也没提到affinity。

        Android应用程序现在分为原生应用(Native App)、Web应用(Web App)、混合应用(Hybrid App)。

        Native App:就是传统地根据Android SDK开发的应用程序APK。

        Web App:就是利用HTML5+CSS3+JavaScript开发的适配移动端的、特像Native App的网页。

        Hybrid App:它就是Native App,但里面只有一个浏览网页的WebView控件,这些网页元素跟本地的元素很像,让用户看起来就像一个正常的本地应用程序一样,网页一般利用H5等技术开发。所以它即可以使用Native App的功能,又拥有Web App的特性。

        关于到底哪种App好的争论一直在继续,Native App可以充分利用SDK给用户炫酷一致的用户体验,但开发成本高、安装包APK较大、升级审核严格。Web App可以跨平台,不管是Android、IOS还是WP,都可以使用相同的网页,开发成本低,但无法达到Native App一样炫酷而灵活的用户体验,无法使用手机的传感器文件系统等资源,也无法管理优化内存。Hybrid App虽然结合了Native App和Web App,拥有这两种的一些优点,但对不稳定网络情况的处理上有欠缺,很难达到一致的用户体验,跨平台的的浏览器版本也会对网页的解析造成影响。

        所以,无所谓谁好谁坏,谁更有前途,只有谁更适合自己公司。对大公司来说,我可以让几十个人的团队做一个原生Native App。而对于小公司来说,没有人会Android,或者不想再招Android开发的人,或者开发成本太高了,所以他们会选择Web App或者响应式网页设计(Responsive Web Design)。对于有几个人的Android团队的公司或者想马上上线产品的大公司,他们会选择Hybrid App作为临时的应用程序。我广东的同学最近一直跟我说HTML5开发的App才有前途,不要总学SDK那一套了,我告诉他,虽然H5现在很火,但只要Android系统还在,原生应用Native App的开发就不会消亡。但我也会持续关注和学习H5和CSS3的新特性。

0 0