https://blog.csdn.net/showdy/article/details/54911239
简单点来理解,可以把栈比作一个开封的箱子,我们可以往里面塞东西,这里假设塞的东西的底面积和箱子的底面积是相同的,那么这些东西就具备有从下往上一定的顺序,当我们想要取出箱子里面的东西时,我们没有办法一下子拿到箱子最底层的东西,我们只能拿到最上面一层的东西,从上往下。当我们每打开一个Activity的时候它就会往Activity任务栈中压入一个Activity,当我们每销毁一个Activity的时候它会从Activity任务栈中弹出一个Activity,由于安卓系统自身的设计,我们只能在手机屏幕上获取当前一个Activity的焦点即栈顶元素(最上面的Activity),其余的Activity会暂居后台等待系统调用。
来看下这张图,这里的箱子就是栈,箱子口可以看作是栈的入口与出口,东西代表数据。栈的特点:具有一定的次序,后进先出(越先放入的东西,越晚出来)。
任务栈是用来提升体验而设计的:
(1) 程序打开时就创建了一个任务栈, 用于存储当前程序的activity,当前程序(包括被当前程序所调用的)所有的activity属于一个任务栈。
(2) 一个任务栈包含了一个activity的集合, 可以有序的选择哪一个activity和用户进行交互,只有在任务栈栈顶的activity才可以跟用户进行交互。
(3) 任务栈可以移动到后台,并且保留了每一个activity的状态. 并且有序的给用户列出它们的任务, 而且还不丢失它们状态信息。
(4) 退出应用程序时,当把所有的任务栈中所有的activity清除出栈时,任务栈会被销毁,程序退出。
启动模式(launchMode)在多个Activity跳转的过程中扮演着重要的角色,它可以解决是否生成新的Activity实例,是否重用已经存在的Activity实例,是否和其他实例共用一个任务栈。任务栈是一个具有栈结构的对象,一个任务栈可以管理多个Activity,每启动一个应用,也就创建一个与之对应的任务栈。
Activity一共有以下四种launchMode模式:1、standard 2、singTop 3、singTask 4、singleInstance,我们可以在AndroidManifest.xml配置<activity>的android:launchMode属性为以上四种之一即可。
1.在Activity启动模式为standard(默认)的情况下,不管之前有没有Activity实例,每一次启动Activity都会创建一个新的Activity实例,并置于Activity任务栈栈顶。
2.在Activity启动模式为singleTop(栈顶任务唯一)的情况下,如果当前Activity处于栈顶,那么它就不会再去实例化一个新的Activity,当Activity不处于栈顶的时候,会重新实例化一个新的Activity并置于栈顶。
3.在Activity启动模式为singleTask(唯一实例)的情况下,当启动Activity的时候,如果当前Activity不存在则实例化一个新的Activity,如果当前Activity在任务栈中已经存在,则会复用这个Activity实例,当启动模式为singTask的时候,启动已经存在在Activity任务栈中但不在栈顶的Activity时,该Activity会把压在它前面的所有Activity弹出任务栈。 设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的任务存在;如果存在这样的任务,它就会在这个任务中启动,否则就会在新任务中启动。因此,如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。
4. 在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦该模式的Activity的实例存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。它的退出顺序是:不再是根据调用顺序,而是在不同的任务栈中,从上往下退出。(每个activity都单独新开一个栈)
singleTop、singleTask和singleInstance模式时,因为重用了实例(不会执行再onCreate()方法),所以会调用onNewIntent方法,且onNewIntent方法是在前一个Activity的onStop方法后(当前ActivityonReStart方法前)立即调用的。界面跳转到一个非standard模式的activty时intent传递的值需要在onNewIntent中获取。
当调用到onNewIntent(intent)的时候,需要在onNewIntent() 中使用setIntent(intent)赋值给Activity的Intent.否则,后续的getIntent()都是得到老的Intent。
<!--获取Activity任务栈 权限-->
<uses-permission android:name="android.permission.GET_TASKS" />
具体实现,获取栈以及其中内容:
// 获取activity任务栈
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.RunningTaskInfo info = manager.getRunningTasks(1).get(0);
// 类名 .ui.mobile.activity.WebsiteLoginActivity
String shortClassName = info.topActivity.getShortClassName();
// 完整类名 com.haofang.testapp.ui.mobile.activity.WebsiteLoginActivity
String className = info.topActivity.getClassName();
// 包名 com.haofang.testapp
String packageName = info.topActivity.getPackageName();
界面跳转是intent.setFlags()
(1) FLAG_ACTIVITY_NEW_TASK: 设置此状态,记住以下原则,首先会查找是否存在和被启动的Activity具有相同的亲和性的任务栈(即taskAffinity,注意同一个应用程序中的activity的亲和性一样,所以下面的a情况会在同一个栈中,前面这句话有点拗口,请多读几遍),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变,如果没有,则新建一个栈来存放被启动的activity
a. 前提: Activity A和Activity B在同一个应用中.
操作: Activity A启动开僻Task堆栈(堆栈状态: A), 在Activity A中启动Activity B, 启动Activity B的Intent的Flag设为
FLAG_ACTIVITY_NEW_TASK, Activity B被压入Activity A所在堆栈(堆栈状态: AB).
原因: 默认情况下同一个应用中的所有Activity拥有相同的关系(taskAffinity).
b. 前提: Activity A在名称为"TaskOne应用"的应用中, Activity C和Activity D在名称为"TaskTwo应用"的应用中.
操作1: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),
在Activity A中启动Activity C, 启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK,
Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 长按Home键, 选择TaskA,
Activity A回到前台, 再次启动Activity C(两种情况1.从桌面启动;2.从Activity A启动,两种情况一样), 这时TaskB回到前台, Activity C显示, 供用户使用, 即:
包含FLAG_ACTIVITY_NEW_TASK的Intent启动Activity的Task正在运行, 则不会为该Activity创建新的Task,
而是将原有的Task返回到前台显示.
操作2: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),
在Activity A中启动Activity C,启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK,
Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 在Activity C中启动
Activity D(TaskB的状态: CD) 长按Home键, 选择TaskA, Activity A回到前台, 再次启动Activity C(从桌面或者ActivityA启动,也是一样的),
这时TaskB回到前台, Activity D显示,供用户使用.说明了在此种情况下设置FLAG_ACTIVITY_NEW_TASK后,会先查找是不是有Activity C存在的栈,根据亲和 性(taskAffinity),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的顺序不变
(2) FLAG_ACTIVITY_CLEAR_TOP:
前提: Activity A, Activity B, Activity C和Activity D在同一个应用中.
操作: Activity A启动开僻Task堆栈(堆栈状态: A), 在Activity A中启动Activity B(堆栈状态: AB), 在Activity B中启动
Activity C(堆栈状态: ABC), 在Activity C中启动Activity D(堆栈状态: ABCD), 在Activity D中启动Activity B,
启动Activity B的Intent的Flag设置为FLAG_ACTIVITY_CLEAR_TOP, (堆栈状态: AB).
(3) FLAG_ACTIVITY_BROUGHT_TO_FRONT:
前提: Activity A在名称为"TaskOne应用"的应用中, Activity C和Activity D在名称为"TaskTwo应用"的应用中.
操作: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),
在Activity A中启动Activity C,启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK,
Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 在Activity C中启动
Activity D(TaskB的堆栈状态: CD), 长按Home键, 选择TaskA, Activity A回到前台, 在Activity A中再次启动Activity C,
在启动Activity C的Intent中设置Flag为FLAG_ACTIVITY_BROUGHT_TO_FRONT, TaskB回到前台,
Activity C显示, (TaskB的堆栈状态: C).
(4) FLAG_ACTIVITY_MULTIPLE_TASK:
与FLAG_ACTIVITY_NEW_TASK结合使用, 首先在Intent中设置FLAG_ACTIVITY_NEW_TASK, 打开Activity,
则启动一个新Task, 接着在Intent中设置FLAG_ACTIVITY_MULTIPLE_TASK, 再次打开同一个Activity,则还会新启动一个Task.
(5) FLAG_ACTIVITY_SINGLE_TOP:
当前Task堆栈中存在ABCD四个Activity, A是栈顶Activity, D为栈底Activity, 存在打开A的Intent中设置了
FLAG_ACTIVITY_SINGLE_TOP标志, 则会使用栈顶A, 而不会从新New A.
(6) FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:
一般与FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET结合使用,如果设置该属性,这个activity将在一个新的task中启动或者或者被带到一个已经存在的task的顶部,这时这个activity将会作为这个task的首个页面加载。将会导致与这个应用具有相同亲和力的task处于一个合适的状态(移动activity到这个task或者从中移出),或者简单的重置这个task到它的初始状态
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET:在当前的Task堆栈中设置一个还原点,当带有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED的Intent请求启动这个堆栈时(典型的例子是用户从桌面再次启动这个应用),还原点之上包括这个应用将会被清除。应用场景:在email程序中预览图片时,会启动图片观览的actvity,当用户离开email处理其他事情,然后下次再次从home进入email时,我们呈现给用户的应该是上次email的会话,而不是图片观览,这样才不会给用户造成困惑。
例: 存在Activity A, Activity B, Activity C, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),
在Activity A中启动Activity B(TaskA堆栈状态: AB), 接着Activity B启动Activity C(TaskA堆栈状态: ABC),
启动Activity C的Intent中设置FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET标题, 这样TaskA中有一个还原点,
当有包含FLAG_ACTIVITY_RESET_TASK_IF_NEEDED的Intent请求TaskA堆栈时(比如请求Activity A)
系统就会将还原点以上的Activity清除, TaskA堆栈中只剩下了AB.