Android基础 - Activity的启动模式
Posted 我叫白小飞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android基础 - Activity的启动模式相关的知识,希望对你有一定的参考价值。
前言:前一篇文章介绍了android的activity的生命周期方法,activity的启动模式也是一个难点,是因为各种启动模式和标示位太容易混淆。为了满足不同的使用场景,我们必须分清这些启动模式。这一篇文章,我们来了解一下Activity的启动模式,也算是一个深入吧,写的不好,请各位多担待。
Activity的LanuchMode
在我们新建activity时,如果不选择启动模式,则默认使用的是standard模式,这种模式在使用过程中,如果我们多次启动该activity,则会在栈里重复创建多个activity实例,单击back键时,则会一一回退,出栈。任务栈是一种“后进先出”的栈结构,意思就是新入栈的任务会放在栈顶,出栈的时候,由栈顶依次出栈。所以我们在使用activity时不可避免的会出现上述问题,导致栈内有多个重复的activity,这是不合理的,所以我们需要分清楚activity的启动模式,在适合的场景下,使用合适的启动模式,这就是我们的目的。首先我们先来看一下activity都有哪些启动模式,然后我们通过实例来分别认识一下它们。启动模式分别有以下四种模式:
- standard模式: 标准模式,也就是默认模式,每次启动一个activity的时候,都会创建一个新的实例,不管这个实例是否存在。被创建的实例,生命周期都符合典型情况下的Activity生命周期。一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。在这种模式下,谁启动了这个activity,那么这个activity就会放在谁的任务栈中。当我们用AoolicationContext 去启动standard模式的activity的时候,就会出现:
Caused 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类型的Context(如ApplicationContext) 并没有所谓的任务栈,所以就会启动失败。解决方法就是为启动的activity指定FLAG_ACTIVITY_NEW_TASK标记位。这样启动这个activity的时候就会创建一个新的任务栈,并且将activity放进任务栈。此时activity其实是以singleTask模式启动的。
具体实例如下:
//启动自己
btn_start_myself.setOnClickListener
var sIntent = Intent()
sIntent.setClass(MainActivity@this,MainActivity::class.java)
startActivity(sIntent)
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
点击3次启动自己,然后打开dos命令行,输入adb shell dumpsys activity,找到如下位置,可以看到,Running activitys 中有4个activity,分别就是刚才启动的3个,再加上初始一个。所以使用该模式时,启动请求都会创建新的activity实例,并放入栈内。
-
singleTop模式: 顾名思义,栈顶复用模式。在这种模式下,如果新activity已经位于栈顶,则新的activity不会被创建,同时会调用它的onNewIntent方法,通过此方法我们可以取出当前请求信息。此模式启动的activity不会调用onCreate、onStart方法,因为该activity没有重建或者重新显示。
示例如下:将上述的MainActivity的启动模式改为singleTop,然后多次点击启动自己,我们先看看生命周期回调日志:
2019-02-16 22:59:02.165 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-16 22:59:02.166 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ MainActivity.onPause(MainActivity.kt:43)
2019-02-16 22:59:02.166 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-16 22:59:02.166 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onPause
2019-02-16 22:59:02.166 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-16 22:59:02.166 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-16 22:59:02.167 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ MainActivity.onNewIntent(MainActivity.kt:79)
2019-02-16 22:59:02.167 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-16 22:59:02.167 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onNewIntent
2019-02-16 22:59:02.167 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-16 22:59:02.167 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-16 22:59:02.168 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ MainActivity.onResume(MainActivity.kt:61)
2019-02-16 22:59:02.168 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-16 22:59:02.168 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onResume
2019-02-16 22:59:02.168 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-16 22:59:02.373 13586-13604/com.xyd.activitylaunchmodedemo I/zygote64: Compiler allocated 6MB to compile void android.view.ViewRootImpl.performTraversals()
2019-02-16 22:59:20.825 13586-13604/com.xyd.activitylaunchmodedemo I/zygote64: Do full code cache collection, code=124KB, data=97KB
2019-02-16 22:59:20.827 13586-13604/com.xyd.activitylaunchmodedemo I/zygote64: After code cache collection, code=104KB, data=68KB
2019-02-16 23:00:03.094 13586-13604/com.xyd.activitylaunchmodedemo I/zygote64: Do partial code cache collection, code=121KB, data=91KB
2019-02-16 23:00:03.095 13586-13604/com.xyd.activitylaunchmodedemo I/zygote64: After code cache collection, code=121KB, data=91KB
2019-02-16 23:00:03.095 13586-13604/com.xyd.activitylaunchmodedemo I/zygote64: Increasing code cache capacity to 512KB
2019-02-16 23:00:33.628 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-16 23:00:33.628 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ MainActivity.onPause(MainActivity.kt:43)
2019-02-16 23:00:33.629 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-16 23:00:33.629 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onPause
2019-02-16 23:00:33.629 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-16 23:00:33.629 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-16 23:00:33.629 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ MainActivity.onNewIntent(MainActivity.kt:79)
2019-02-16 23:00:33.629 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-16 23:00:33.629 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onNewIntent
2019-02-16 23:00:33.629 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-16 23:00:33.630 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-16 23:00:33.630 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ MainActivity.onResume(MainActivity.kt:61)
2019-02-16 23:00:33.630 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-16 23:00:33.630 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onResume
2019-02-16 23:00:33.630 13586-13586/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
然后我们在看看栈内activity的数量:
所以就算是多次点击,栈内也还是只有一个activity。
如果我们用另一个activity启动singleTop模式的activity,看一下是否能复用。
SecondActivity部分代码:
//启动第一个activity
btn_start_1.setOnClickListener
var sIntent = Intent()
sIntent.setClass(SecondActivity@this,MainActivity::class.java)
startActivity(sIntent)
将MainActivity的启动模式改为singleTop:
<activity android:name=".SecondActivity">
</activity>
<!--默认就是standard模式-->
<activity android:name=".MainActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
运行之后,在MainActivity中启动SecondActivity,然后在SecondActivity中启动MainActivity,此时我们再看栈内activity的情况:
可以看到此时栈内有3个activity,分别是两个MainActivity和一个SecondActivity,由此说明singleTop只是在该activity在栈顶时才能复用。
-
singleTask模式:栈内复用模式。这是一种单实例模式,这种模式下,只要是栈内存在该activity实例,多次启动后不会创建新的实例,而是会复用该activity,并且调用onNewIntent方法。例如:Activity A 是singleTask模式启动的,再次启动时,系统会先在栈内找是否存在A的实例的任务栈,如果不存在,则会创建新的任务栈,并将A的实例放在栈中,如果存在A所需的任务栈,则需要看该栈中是否存在A的实例,如果存在则直接调用onNewIntent方法,如果不存在,则创建A的实例。
还是上述两个activity,但是我们修改一下MainActivity的启动模式,并且操作步骤还是上述步骤,我们看一下栈内activity的情况:
此时我们可以看到栈内只有一个activity,这就是singleTask的另一个特性,就是说如果singleTask模式的activity在栈内存在,并且在它之上还有别的activity,则再次启动这个activity的时候,在它之上的所有activity全部出栈,然后直到该activity位于栈顶截止。
-
singleInstance模式:但是萝莉模式。这是一种加强的singleTeask模式。此模式的activity只会单独存在以一个任务栈中。例如:activity A 是以singleInstance模式,当A 启动后,系统会为它创建一个单独的任务栈,并将A放入栈中,后续的请求不会再创建新的A,除非这个任务栈被销毁。
我们将上述MainActivity的启动模式改为singleInstance,然后由MainActivity启动SecondActivity,然后由SecondActivity启动MainActivity,此时查看栈内情况如下:
我们会发现一个问题,栈内现在只有两个activity实例,而SecondActivity启动模式为standard,照理说,应该存在多个activity的,但是为什么只有两个呢?我们来看一下生命周期日志:
2019-02-17 00:23:34.490 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.491 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ MainActivity.onPause(MainActivity.kt:42)
2019-02-17 00:23:34.491 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-17 00:23:34.491 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onPause
2019-02-17 00:23:34.491 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.539 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.540 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ SecondActivity.onRestart(SecondActivity.kt:57)
2019-02-17 00:23:34.540 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-17 00:23:34.540 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onRestart
2019-02-17 00:23:34.540 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.540 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.541 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ SecondActivity.onStart(SecondActivity.kt:39)
2019-02-17 00:23:34.541 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-17 00:23:34.541 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onStart
2019-02-17 00:23:34.541 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.541 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.542 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ SecondActivity.onResume(SecondActivity.kt:45)
2019-02-17 00:23:34.542 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-17 00:23:34.542 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onResume
2019-02-17 00:23:34.542 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.586 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.587 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ MainActivity.onSaveInstanceState(MainActivity.kt:84)
2019-02-17 00:23:34.587 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-17 00:23:34.587 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onSaveInstanceState
2019-02-17 00:23:34.587 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.588 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➀: ╔══════════════════════════════════════════════════════════════
2019-02-17 00:23:34.588 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➁: ║ MainActivity.onStop(MainActivity.kt:66)
2019-02-17 00:23:34.588 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➂: ╟──────────────────────────────────────────────────────────────
2019-02-17 00:23:34.588 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➃: ║ onStop
2019-02-17 00:23:34.588 18292-18292/com.xyd.activitylaunchmodedemo D/LogUtils➄: ╚══════════════════════════════════════════════════════════════
由MainActivity再次启动SecondActivity时,没有重新创建activity,只是重新显示出来,调用了onRestart方法。这个问题后续研究。
未完待续。。。。。
以上是关于Android基础 - Activity的启动模式的主要内容,如果未能解决你的问题,请参考以下文章