1.简介
Android四大启动模式分别为Standard,SingleTop,SingleTask,SingleInstance,其中前面三种平时使用的比较多此处不多做解析,重点分析下SingleInstance这种启动模式。SingleInstance为栈内单实例模式,顾名思义就是使用该模式下的Activity创建时候,如果该对象没有被创建则会独立开辟栈来存储该Activity的实例,如果被创建了就直接使用,生命周期的回调跟SingleTask类似,主要不同的是SingleInstance栈内只有一个实例。
2.SingleTask与SingleInstance区别
其他Activity跳转到SingleInstance的Activity时会明显感觉出来是任务的切换,就像一个App去拉起另外一个App的效果。原因很简单,SingleInstance不只开启了独立栈,也默认开启了独立的任务(但该独立任务在系统后台不会独立展示,需要配置taskAffinity才独立展示),而SingleTask不会开启独立栈,也不会开启独立任务,需要配置taskAffinity不同于当前页面才会创建独立任务并在系统独立展示。如果想去掉任务切换效果有两个方案:
1.去掉任务切换动画(通过style给Activity设置)
2.通过startActivityForResult跳转 (推荐)
通过该方法跳转默认使用Context所在Actiivty的任务taskId,相同的taskId自然就相当于在同一个任务中跳转,所以没有任务之间切换的效果了。
3.SingleInstance和其他启动模式Activity间的切换
3.1 ActivityA打开SingleInstance的ActivityB,之后home键回到手机桌面,之后再点击图标打开该App会直接打开ActivityA,因为点击图标打开时候系统拉起的是该App的主任务(App根页面所在的任务),而不是独立栈独立任务的ActivityB。
处理方法:自定义AtyManager类管理当前Activity的打开列表,BaseActivity中onCreate和onDestory和finish中分别重写add和remove方法(注意onDestory会有延迟所以在finish也remove一次)。在ActivityA中onResume判断home回到桌面时的页面任务id不同于ActivityA任务id则通过startActivity打开或者ActivityManager的moveTaskToFront方法拉起对应任务。
3.2 ActivityA打开SingleInstance的ActivityB,之后menu键查看手机后台启动任务,之后直接点击ActivityB打开,再finish掉ActivityB会直接回到手机桌面(像闪退一样)。因为当menu键按下的时候其实系统全部任务回到系统后台,再从任务列表中打开则只是打开当前独立的任务,所以底下打开的已经没有了ActivityA所在的任务,自然ActivityB返回就直接到了手机桌面。
处理方法:同上,ActivityB finish的时候判断上一个页面是否和当前任务id相同,不同则通过startActivity打开或者ActivityManager的moveTaskToFront方法拉起对应任务。
3.3 Android 11上在SingleInstance打开的Activity按home键再点桌面图标发现App被重启了。原因Android11做了任务中不用或不在最上层的栈清理工作。添加taskAffinity不同于主任务可以解决该问题,但在手机后台任务列表中会多出该任务的展示。在任务的根Activity设置excludeFromRecents="true",用于不展示当前任务到系统后台任务列表,然而这个api是个坑,当前App在前台的时候menu按键看到还是会有多个任务在系统,但如果当前App不在前台按menu则看到该App只有唯一的系统任务,所以我觉得不适用。为兼容Android 11上SingleInstance页面问题,只能是设置taskAffinity让其多个后台任务(参考微信的小程序就是SingleInstance方案)
4.总结
SingleInstance还是坑不少的,非必要请勿用。如果非要用则遇坑填坑,干不掉bug就干掉需求,干不掉需求就干掉提需求的人(*^__^*)