安卓Activity的启动模式

安卓Activity的启动模式,第1张

安卓Activity的启动模式

文章目录

Activity的启动模式

StandandSingleTopSingleTaskSingleInstance Activity的Flags

Activity的启动模式

  Android中,Activity的存储结构是栈,栈是一种先进后出的数据结构,用栈存储Activity也符合我们的 *** 作习惯(后打开的页面会覆盖先打开的页面,按下返回键时,我们希望看到之前的页面。
  为什么需要有Activity启动模式呢,正常来说,一个APP会有一个Activity返回栈,但是特殊场景下,也有一个APP需要两个返回栈的场景。再比如我们连续启动多个一样的Activity,那么系统会创建多个Activity的实例,并依次入栈,这样看起来有点多余,所以Android系统提供了四种启动模式:standand、singleTop、singleTask和singleInstance。

Standand

  标准模式,如果我们不指定Activity的启动模式,那么默认的Activity启动模式就是Standand(标准模式)。
  标准模式下,启动相同的Activity,系统会创建多个Activity,如下图:
  多次创建Activity1,会出现多个实例,比如栈中有4个相同的Activity,需要按下4次back键才能退出APP。也就是说standard模式下,只要我们创建新的Activity,就会再栈中压入该Activity,不管该Activity是否已经存在,并且由于重新创建了Activity,生命周期函数onCreate、onStart、onResume也会被调用。

SingleTop

  即栈顶复用模式,如果要启动的目标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

  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。

Activity的Flags

    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开发艺术探索》

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5708946.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存