Activity的启动模式
StandandSingleTopSingleTaskSingleInstance Activity的Flags
Activity的启动模式 Android中,Activity的存储结构是栈,栈是一种先进后出的数据结构,用栈存储Activity也符合我们的 *** 作习惯(后打开的页面会覆盖先打开的页面,按下返回键时,我们希望看到之前的页面。
为什么需要有Activity启动模式呢,正常来说,一个APP会有一个Activity返回栈,但是特殊场景下,也有一个APP需要两个返回栈的场景。再比如我们连续启动多个一样的Activity,那么系统会创建多个Activity的实例,并依次入栈,这样看起来有点多余,所以Android系统提供了四种启动模式:standand、singleTop、singleTask和singleInstance。
标准模式,如果我们不指定Activity的启动模式,那么默认的Activity启动模式就是Standand(标准模式)。
标准模式下,启动相同的Activity,系统会创建多个Activity,如下图:
多次创建Activity1,会出现多个实例,比如栈中有4个相同的Activity,需要按下4次back键才能退出APP。也就是说standard模式下,只要我们创建新的Activity,就会再栈中压入该Activity,不管该Activity是否已经存在,并且由于重新创建了Activity,生命周期函数onCreate、onStart、onResume也会被调用。
即栈顶复用模式,如果要启动的目标Activity刚好在栈顶,那么不会重新创建Activity,并且会调用栈顶Activity的onNewIntent方法。
SingleTask 栈内复用模式,启动一个singleTask的Activity时,首先判断该Activity指定的栈是否存在(不指定栈名为app包名),如果存在,只要栈内存在目标Activity,那么多次启动该Activity不会重新创建,而是将目标Activity之上的所有Activity出栈,让目标Activity处于栈顶,并调用onNewIntent方法,如果栈内不存在Activity,直接创建新的Activity实例压入栈中。如果栈不存在,则创建新的栈,并将该Activity实例压入新栈,如下流程图:
思考:Activity1(standand)启动Activity2(singleTask),Activity2启动Activity3(standand),会产生多少个栈,栈内分别有多少个Activity?
这里我们分情况讨论,除指定launchMode为singleTask之外还区分是否有指定taskAffinity属性:
Activity2只指定为singleTask,不指定taskAffinity,不指定taskAffinity表示要启动的Activity2会进入默认的栈(默认栈名为app包名),那么运行结果如下:
onCreate activity1, taskId 195 onCreate activity2, taskId 195 onCreate activity3, taskId 195
除了指定activity2的launchMode为singleTask之外,指定activity2的taskAffinity为"a.b.c",这里的taskAffinity只要不和包名相同既可。
运行结果:
onCreate activity1, taskId 197 onCreate activity2, taskId 198 onCreate activity3, taskId 198
不难看出,与情况1不同,启动activity2(singleTask+taskAffinity不是包名)后,activity2进入了新的栈,且在activity2上启动的activity3也进入了activity2所在的栈。
singleInstance是加强版的singleTask,除了具有singleTask模式的所有特征外,还有一点,singleInstance模式下的activity,会单独占有一个返回栈。并且,如果启动的activity是singleInstance模式,安卓系统的切换动画是task间的切换,这是安卓系统刻意的提醒。
思考1:Activity1(standand)启动了Activity2(singleInstance)启动了Activity3,会产生多少个栈,栈内分别有多少个Activity?
答案是有两个栈,栈1有activity1和activity3,栈2有activity2
思考2:当前看到的activity是3,如果连续按下两次back键,会依次看到哪些activity。
答案是activity3 -> activity1 -> activity2,按下back键后,会在当前的返回栈(stack1)进行回退,等stack1的元素空之后,再回退activity2。
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_NEW_TASK的作用,相当于在manifest.xml中指定launchMode为singleTask。
1)在Activity中使用时,需要指定taskAffinity与包名不同:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) findViewById(R.id.tv).setOnClickListener { val intent = Intent(this, MainActivity2::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) startActivity(intent) } }
AndroidManifest.xml
运行结果:
onCreate MainActivity1 taskId:4730
onCreate MainActivity2 taskId:4731
2)在service中启动一个activity时,会出现异常:
aused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
我们知道如果从activity中打开另一个activity,默认会放入当前activity的栈,但是我们在service中使用的context是service,所以被打开的activity不知道进入哪个栈,所以需要加上FLAG_ACTIVITY_NEW_TASK
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { val i = Intent(this, MainActivity2::class.java) i.flags = Intent.FLAG_ACTIVITY_NEW_TASK startActivity(i) return super.onStartCommand(intent, flags, startId) }
运行结果:
onCreate MainActivity1 taskId:4786
onCreate MainActivity2 taskId:4786
可见其实MainActivity1和MainActivity2也是进入同一个栈
FLAG_ACTIVITY_SINGLE_TOP
与在AndroidManifest.xml中设置singleTop一个效果
FLAG_ACTIVITY_CLEAR_TOP
假如现在已经启动了Activity1,2,3,现在从activity3中启动activity2,并设置FLAG_ACTIVITY_CLEAR_TOP标签,则栈内只剩下activity1,2,并且activity2重新onCreate,不会走onNewIntent。
val intent = Intent(this, MainActivity2::class.java) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP startActivity(intent)
想要走onNewIntent不走onCreate,可以多加一个FLAG_ACTIVITY_SINGLE_TOP
参考书籍《android开发艺术探索》
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)