任务栈,我们说过任务栈的概念,也知道了它的作用,但是在使用过程中会有一些坑。
指定任务栈:
<activity
android:name=".Main2Activity"
android:launchMode="standard"
android:taskAffinity="com.net.wrf"/>
这个时候就给此Activity指定了它的任务栈,但是它起不起作用还是得具体分析。
比如现在有两个Activity,A和B,App首先进入A,启动模式都为standard,并且为B指定taskAffinity属性,因为不指定的话就默认为应用包名,所以这样指定了就相当于为B创建一个名为com.net.wrf的任务栈,那么事实是这样吗?
启动A:
03-13 16:05:24.036 17192-17192/? I/mydata: Main3Activity...onCreate
03-13 16:05:24.036 17192-17192/? I/mydata: Main3Activity..taskId..1630
03-13 16:05:24.037 17192-17192/? I/mydata: Main3Activity...onStart
03-13 16:05:24.037 17192-17192/? I/mydata: Main3Activity...onResume
A启动B:
03-13 16:05:30.185 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onPause
03-13 16:05:30.231 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onCreate
03-13 16:05:30.231 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main2Activity..taskId..1630
03-13 16:05:30.231 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStart
03-13 16:05:30.232 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onResume
03-13 16:05:30.688 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStop
可以发现,B还是进入了A所在的任务栈,那么taskAffinity没起作用。
那么还有一种情况,就是我们不改变上面的配置,A中启动一个Service,在Serivce内启动B:
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
Log.i("mydata","startActivity");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent1 = new Intent(MyIntentService.this,Main2Activity.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent1);
}
},3000);
return super.onStartCommand(intent, flags, startId);
}
我们必须加上标记为Intent.FLAG_ACTIVITY_NEW_TASK,否则无论如何都启动不了。
那么这种方式启动的B会发生什么呢?
03-13 16:08:37.171 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onCreate
03-13 16:08:37.171 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity..taskId..1633
03-13 16:08:37.172 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStart
03-13 16:08:37.172 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onResume
03-13 16:08:57.788 19176-19176/ryrj.pzfw.net.activitytest I/mydata: startActivity
03-13 16:09:00.856 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onPause
03-13 16:09:00.916 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onCreate
03-13 16:09:00.916 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main2Activity..taskId..1634
03-13 16:09:00.917 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStart
03-13 16:09:00.917 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onResume
03-13 16:09:01.639 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStop
所以总结一下:并不是指定了FLAG_ACTIVITY_NEW_TASK,就要为所启动的activity创建新的任务栈。
并且Android艺术探索与开发上任主席说FLAG_ACTIVITY_NEW_TASK的作用相当于在XML文件中指定singleTask模式,我觉得这个是不对的,你不信在一个service中多次使用这个标记启动一个standard模式的activity,并不会调用onNewIntent,会一直重建实例,和singleTask效果并不一样。有图有证据:
03-13 16:25:55.495 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onCreate
03-13 16:25:55.496 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity..taskId..1647
03-13 16:25:55.496 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStart
03-13 16:25:55.496 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onResume
03-13 16:26:00.962 30665-30665/ryrj.pzfw.net.activitytest I/mydata: startActivity
03-13 16:26:04.008 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onPause
03-13 16:26:04.064 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onCreate
03-13 16:26:04.065 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity..taskId..1647
03-13 16:26:04.065 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStart
03-13 16:26:04.066 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onResume
03-13 16:26:04.537 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStop
03-13 16:26:08.559 30665-30665/ryrj.pzfw.net.activitytest I/mydata: startActivity
03-13 16:26:11.608 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onPause
03-13 16:26:11.651 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onCreate
03-13 16:26:11.651 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity..taskId..1647
03-13 16:26:11.652 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStart
03-13 16:26:11.652 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onResume
03-13 16:26:12.117 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStop
有人说想要想达到singleTask的效果,必须得用两个标记位:
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
而Android开发与探索中对FLAG_ACTIVITY_CLEAR_TOP的解释是,清空它以及它之上的实例,确实是如此,但是并不会回调onNewIntent方法(因为前面的那个相同Activity实例已经被销毁了),还是有一点区别的。
在Service中启动一个Activity如何达到singleTop效果:
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
这个确实可以达到singleTop效果,并且onNewIntent方法也会被回调。
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
这个确实会保证一个栈中只有一个实例,但是它却是每次都情况栈,然后创建一个新的实例入栈的,不会复用,也不会调用onNewIntent方法。
所以总结:在Service或BoardCastReceiver中启动Activity时一定要加上FLAG_ACTIVITY_NEW_TASK标记,并且请勿使用诸如CLEAT_TOP或者CLEAT_TASK来达到singleTask或者singleInstance的效果,因为却是表现一样,但实质不一样,还是去XML中指定的为好。
好了,现在来在正常activity中通过标记来启动activity实验:
FLAG_ACTIVITY_NEW_TASK :
场景A加上标记启动B,不会为B创建新栈,B启动A,然后再次A启动B,也不会出现出栈的情况,栈中实例情况为ABAB,所以我觉得它自己使用时没用。
FLAG_ACTIVITY_CLEAR_TOP:
场景A加上标记启动B,创建B,B启动A,创建A,这时是ABA,A再启动B,则BA出栈,创建一个新的A的入栈。
FLAG_ACTIVITY_CLEAR_TASK:
场景A加上标记启动B,创建B,B启动A,然后A再启动B,没有任何影响。。
FLAG_ACTIVITY_SINGLE_TOP:
场景A加上标记启动B,创建B,B启动A,然后A再启动B,没有任何影响。。
总结一下:这些标记单独使用,只有clearTop是起作用的,其余的不起作用。
然后我就试了一下上面在service中组合使用的情况下,发现使用Service中的组合情况是有效果的,并且和Service中的效果是一样的。有人可能会说为什么在Service中就要使用组合呢,因为Service启动Activity必须得加上FLAG_ACTIVITY_NEW_TASK,所以实验的使用实验其他三种标志也必须与这个标记组合。
所以,一般情况下不要依赖使用标记,这个产生的效果不是很好。请在配置文件中配置。