Activity的启动模式
当我们点击这个推倒后台的任务键的时候我们看到的是什么?一个个Activity?一个个App?其实我们看到的时一个个Task也就是我们说的后台任务,当我们的桌面图标,在桌面被点击的时候,App的默认Activity也就是那个在清单文件配置了MAIN+LAUNCHER的intent+filter的Activity会被启动,并且这个Activity会被放进系统刚创建的一个Task里面,我们通过最近的任务键,可以在多个App之间切换,其实更精确的说,我们是在多个Task之间切换,每个Task都有一个自己的回退栈,他按顺序记录了用户打开的每个Activity,这样就可以用户再按返回键的时候,按照倒叙来一次关闭这些Activity,当回退栈里面最后一个Activity被关闭,这个Task生命也就被结束了,但是他并不会在最近的任务列表里面消失,系统依然会保留这个Task的一个残影给用户,目的就让用户可以更方便的切回去,只是这种行为的切回去是对App的重新启动,因为原先的那个Task已经不存在了,所以在最近任务里看到的Task,未必是活着的。Activity是一个可以跨进程,跨应用的组件。当你在A App打开B App的 Activity的时候这个Activity会直接被放进A的Task里,而对于B的Task是没有任何影响的。因为他提供的是一个通用的功能,比如通讯录App,可能会提供一个添加联系人的Activity供其他App使用,比如我们从短信的App里面点击一个电话,选着新建联系人,然后通讯录App提供的添加联系人Activity就会被打开,那这个页面是和谁相关的?和短信相关吗,当然相关,因为他就是从短信跳过来的,他们在一整个逻辑链条上的。如果现在按了返回键,就会回到刚才的短信界面,和通讯录先关吗,这个时候是不相关的。所谓不相关就是当用户按下最近任务键的时候,这时是看不到通讯录相关的Task,如果这个时候回到桌面点击通讯录的图标,这个时候看到的也不是添加联系人的页面,而是一个联系人列标的页面。如果这个时候切回短信App这个时候就会回到添加联系人的页面,继续编辑添加联系人的信息,这个时候就是和打开他的App先关而不是提供他的,确切的说是和打开他的Task相关。也就是在不同的Task里面打开同一个Activity,Activty会被创建多个实例,分别放进每一个Task,互不干扰,这是为了符合产品逻辑和用户习惯的。但是如果这个时候点击的不是电话号码而是邮箱地址,那么这个时候我的邮箱App提供的编写邮件的Activity就会被打开,这个时候这个编写邮件的Activity就会和短信App相关也会和邮箱App相关。这个时候如果用户点击任务键就会看到邮箱App的Task会出现在短信Task的旁边,并且如果点击这个Task或者切回桌面点击邮件的图标,都会回到邮件的界面继续写。这两个列子并没有本质上的区别,只是用户的心里预期决定了产品的设计逻辑。如果我们要写这个类似邮件的功能Activity我们只需要在清单 文件里面配置sIngleTask。
SingleTask会让Activty被别的App启动的时候,不会进入启动他的Task里面,而是会在属于他自己的Task里面创建,放在自己的栈顶。然后会把这一整个Task拿过来压在启动他的Task的上面,这个逻辑就可以保证不管从哪个App启动被标记为SingleTask的Activity,总会被放在自己 的Task里面。仔细观察会发现这种方式打开的Activity的入场动画应该是应用间切换的动画,而不是普通的Activity的入场动画。同时做到提醒用户在做跨任务的操作。如果这个时候用户点击返回键,界面会显示你的App里面的上一个Activity,而不是返回到之前的App,知道用户反复按返回键,把这个App的所有Activity全部关闭了,上面的Task消失,下面的Task才会出来,而且切换动画又是应用间切换的动画,确切的说是Task之间切换的动画,所以不止Activty在Task内部可以叠成栈,也可以在不同Task之间叠起来。不过这种叠加只适用于前台的Task,前台叠加了多个Task,在进入了后台的第一时间就会被拆开。前台进入后台最常见的有两种,按Home键返回到桌面,以及按最近任务键查看最近任务。需要注意的是前台Task,在最近任务列表显示出来的时候就已经进入到后台,而不是在切换到其他应用之后。所以用户从短信进入到邮箱之后,没有之间按返回键,而是先查看一下最近任务,在马上切回去,这个时候虽然表面上看着没变,但实际上前台Task就已经只剩一个了。现在如果用户,再连续按返回键关闭邮件的App的Task,他就不会返回到短信了。而是直接回桌面。如果我们不是设置启动模式为SingleTask,我们也可以通过设置allowTaskReparenting属性设置为true,那么当用户从短信里打开这个Activity的时候,他虽然会依然进入短信App的Task里面。但当稍后用户,再从桌面点击邮件App的时候,原先放在短信Task的Activity会被挪过来,放进邮件的App的Task里面,在回退栈的顶端被显示出来,而这个时候你在切回短信,也会发现那个Activity已经不见了,所以这个时候的打开并没有Task之间的切换,所以也就没有夸张的入场动画了。SingleTask除了保证在固定的Task里面创建,还有一个行为规则,如果启动的时候这个Task的栈里面,已经有了这个Activity,那么就不会再创建新的对象,而是直接复用这个已有的对象,所以自然不对在调用他的oncreat()方法,而调用他的onNewIntent()方法,让他可以从Intent里面解析数据来刷新界面,类外在调用onNewIntent()之前如果这个Activity上面还压在其他的Activity,系统也会把这些Activity全部清楚。来确保我们的Activity出现在我们的栈顶。那这样的SingleTask,既保证了一个Task里面只有这个Activity,有保证了这个Task里最多只有一个Activity,所以虽然他的名字叫做SingleTask,但是他实际上限制了它所修饰的Activity,在全局只有一个对象。
SingleInstance,刚说道SingleTask其实是一个事实上的全局单列,其实这个SingleInstance他的行为逻辑和SingleTask基本是一致的,只是他多了一个更严格的限制,他要求他所在的Task里面只有这一个Activity,下面不许有旧的上面也不许有新的,比如我们把编写邮件的Activity的启动模式设置为SingleInstance,那么用户在短信App里面点击了邮件地址的时候,邮件的App不仅会创建这个Activity对象,而且会创建一个单独的Task,来吧这个Activity放进去,或者之前如果已经创建过了,这个Task的Activity了,那么就像SingleTask一样直接复用这个Activity,调用他的onNewIntent(),列外这个Task也会被拿过来压在短信的这个Task上面,入场动画是切换Task的动画,如果这个时候用户点击返回键,上面这个Task因为只有一个Activity,所以手机会直接返回到短信的App,出场动画也是切换Task的动画,如果用户没有直切点击返回而是切换了一下最近任务,又返回回来,这时候因为下面的短信的Task,已经被推到后台,再点返回的时候就不是回到短信的App而是返回到短信的App。如果用户既没有点击返回也没有切换到后台,而是在编写邮件的Activity又启动了新的Activity,由于SingleInstance的限制,这个新打开的Activity并不会进入当前的Task,而是会被装进列一个Task里面,然后随着这个Task一起被拿过来压在最上面。这就是SingleInstance和SingleTask的区别。singleTask强调的只是唯一性,我只会在一个Task里面出现,而且这个Task里面也就只有一个我的实例,而SingleInstance除了强调唯一性,还要求独占性,要独自霸占一个完整的Task,在实际的操作中,他们的区别就是,在被启动之后,用户按返回键的时候,singleTask会在自己的App里面进行回退,而SingleInstance会直接回到原先的App,以及用户稍后从桌面,点开Activity所在的App的时候,singleTask会看到,这个Activity依然在栈顶,而SingleInstance的会看到这个Activity已经不见了,当然只是看不到了,并没有被杀死,当你再次启动他的时候,他就会再次跑到前台来,并且调用onNewIntent()的回调,所以在最近任务里面看不见Task的也未必就死了。
网友评论