android 应用程序中,一般都会发生activity的跳转和返回键的点击操作,而这就会涉及到activity启动模式问题。 首先引入任务栈Task的概念,(本篇文章不过多解释Task和Back Stack,没太多影响)Task可以理解为是一个容器,启动一个应用,系统就会创建一个Task用来存放主activity, 1、在默认情况下,以后新打开的activity都会放在同一个Task中, 2、即使Task里边已经有了某个activity的实例,在每一次跳转到该activity时,都会再创建一次。 3、Task遵循后进先出的规则,即后打开的activity会处于Task的顶部,当点击返回键时,后打开的activity首先被清除出Task。
上边的第3点是恒定不变的,第1和第2点,则可以在清单文件中通过设置属性android:launchMode的值即设置activity的启动模式来进行改变。 activity有四种启动模式:standard、singleTop、singleTask 和 singleInstance,如不配置,默认是standard的。
在Activity类中,有一个getTaskId()方法,我们可以通过它获取当前activity所在的任务栈的ID,getTaskId()方法的API注释为:Return the identifier of the task this activity is in.This identifier will remain the same for the lifetime of the activity.
下边用一个demo来说明activity的四种启动模式: 共3个Activity:MainActivity、FirstActivity 和 SecondActivity,它们的布局文件都一样,只在最底部放一个button用来跳转:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.hwgt.launchmode.MainActivity" >    <Button         android:id="@+id/bt_Jump"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_marginBottom="13dp"        android:layout_centerHorizontal="true"        android:text="跳转到 FirstActivity"        android:textSize="15dp"/></RelativeLayout></span></span>
3个Activity中逻辑都一样: 第一、处理button的点击事件:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">//MainActivity:Intent intent = new Intent(MainActivity.this, FirstActivity.class);MainActivity.this.startActivity(intent);//FirstActivity:Intent intent = new Intent(FirstActivity.this, SecondActivity.class);FirstActivity.this.startActivity(intent);//SecondActivity:Intent intent = new Intent(SecondActivity.this, MainActivity.class);SecondActivity.this.startActivity(intent);</span></span>
第二、onCreate()方法中打印Log.d("HWGT", "onCreate----"+getTaskId()+"----"+this.toString()); onNewIntent()方法中打印Log.d("HWGT", "onNewIntent----"+getTaskId()+"----"+this.toString());
standard:每一次都重新创建实例 3个Activity的启动模式都为standard时,log打印情况如下: getTaskId()的值保持不变,并且每一次跳转都在创建新的实例 现在更改SecondActivity中的跳转逻辑为:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">Intent intent = new Intent(SecondActivity.this, SecondActivity.class);SecondActivity.this.startActivity(intent);</span></span>
log打印情况如下: 依然是getTaskId()的值保持不变,并且每一次跳转都在创建新的实例
singleTop:即使栈内有,只要栈顶没有就重新创建,栈顶有就不创建 现在更改SecondActivity的启动模式为singleTop,则log打印情况如下 getTaskId()的值保持不变,栈顶有SecondActivity的实例时,就直接复用,并且onNewIntent()方法得到执行
singleTask :栈内唯一,且会将位于该实例之上的activity全部销毁 现在更改SecondActivity中的跳转逻辑为:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">Intent intent = new Intent(SecondActivity.this, FirstActivity.class);SecondActivity.this.startActivity(intent);</span></span>
并且更改FirstActivity的启动模式为singleTask,则log打印情况如下: 可以看到,在从SecondActivity跳到FirstActivity时,SecondActivity被销毁了。
singleInstance:创建一个新的Task来存放activity 如果一个activity的启动模式被设置为singleInstance,那么启动时,会为该activity单独创建一个Task。 现在将SecondActivity的启动模式改为singleInstance,MainActivity和FirstActivity的启动模式改为standard,三个activity中的跳转逻辑改为:
<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Microsoft YaHei;font-size:14px;">//MainActivity:Intent intent = new Intent(MainActivity.this, FirstActivity.class);MainActivity.this.startActivity(intent);//FirstActivity:Intent intent = new Intent(FirstActivity.this, SecondActivity.class);FirstActivity.this.startActivity(intent);//SecondActivity:Intent intent = new Intent(SecondActivity.this, MainActivity.class);SecondActivity.this.startActivity(intent);</span></span>
log打印情况如下: 并且在第一次跳转到SecondActivity时,查看打开的应用列表可以发现,名为launchmode的应用图标出现了两个,这两个图标分别对应着id为44和45的Task,随便点击一个进入到launchmode应用,这个时候可以发现,点击跳转或返回键的时候,activity的清除顺序已经由对应的Task所存储activity实例的顺序决定了,singleInstance这种启动模式适用于多个应用共享一个activity的情况。
总结一下: activity的四种启动模式解决了什么问题呢? 答案是,在Task遵循后进先出的规则(即后打开的activity会处于Task的顶部,当点击返回键时,后打开的activity首先被清除出Task)的前提下, 1、定义了要不要重新创建一个Task来存储新打开的activity。 2、定义了新打开一个activity时,需不需要再创建一个实例(即使已经存在)。 3、定义了新打开一个activity之后,任务栈Task里边activity实例的堆叠顺序,这将直接决定连续点击返回键时的退出顺序。 那么,activity的四种启动模式没有解决的有什么问题呢? 1、如果要用不同于打开新activity的activity所在的那个Task 的Task来存储新打开的activity,那么,该用哪个Task?用已经存在的,还是重新创建一个?如果用已经存在的,那么用哪个?依据是什么? 2、比如有一个activity A,我们已经在清单文件中规定了,它的启动模式为standard,目前任务栈中的堆叠顺序为:ABCD,现在的需求是,从D跳转到A,并且跳转到A之后,任务栈中的堆叠顺序为:A,即只留下A,这又怎么实现呢?当然,直接把BCD finish掉也可以,但一定会遇到其他的只靠启动模式不好解决的问题,即启动模式有些时候不够灵活。
由于activity的四种启动模式没有解决的这些问题,我们引入了以下两个概念: 1、affinity 一个activity的affinity 用来标识它属于哪个Task,可以在清单文件中设置taskAffinity的值来改变,理论上拥有相同affinity的activity同属于一个Task,如果不进行设置的话,都从application的affinity继承而来,而application的affinity默认为清单文件中的包名 2、intent 的 flag 就是在用Intent开启一个Activity时,在Intent中加入flag标志。如果同时设置了要打开的activity的启动模式,则flag的优先级更高。两种方式的差别在于,前者在于描述自己,声明自己应该以何种方式被加载,而后者则是主动声明要以何种方式加载一个Activity。最常用的几个flag为: FLAG_ACTIVITY_NEW_TASK: (下边文字摘自网络,谢谢作者!) 当Intent对象包含这个标记时,系统会寻找或创建一个新的task来放置目标Activity,寻找时依据目标Activity的taskAffinity属性进行匹配,如果找到一个task的taskAffinity与之相同,就将目标Activity压入此task中,如果查找无果,则创建一个新的task,并将该task的taskAffinity设置为目标Activity的taskActivity,将目标Activity放置于此task。注意,如果同一个应用中Activity的taskAffinity都使用默认值或都设置相同值时,应用内的Activity之间的跳转使用这个标记是没有意义的,因为当前应用task就是目标Activity最好的宿主。

FLAG_ACTIVITY_SINGLE_TOP

这个FLAG就相当于加载模式中的singletop,比如说原来栈中情况是A,B,C,D在D中启动D,栈中的情况还是A,B,C,D

FLAG_ACTIVITY_CLEAR_TOP

这个FLAG就相当于加载模式中的SingleTask,这种FLAG启动的Activity会把要启动的Activity之上的Activity全部弹出栈空间。类如:原来栈中的情况是A,B,C,D这个时候从D中跳转到B,这个时候栈中的情况就是A,B了

FLAG_ACTIVITY_BROUGHT_TO_FRONT

这个网上很多人是这样写的。如果activity在task存在,拿到最顶端,不会启动新的Activity。这个有可能会误导大家! 他这个FLAG其实是这个意思! 比方说我现在有A,在A中启动B,此时在A中Intent中加上这个标记。此时B就是以FLAG_ACTIVITY_BROUGHT_TO_FRONT 这个启动的,此时在B中再启动C,D(正常启动C,D),如果这个时候在D中再启动B,这个时候最后的栈的情况是 A,C,D,B.特别注意的是,我上面说的网上人描述的这个FLAG,会很容易让人误解成这样,A,B,C,D都是标准加载,然后我在D中启动A,这个intent加上FLAG_ACTIVITY_BROUGHT_TO_FRONT,就会误认为变成B,C,D,A!!其实不是,这个时候应该是A,B,C,D,A.不信的人大家试试看。不过下面这个标记和这个标记就会让大家明白了!

FLAG_ACTIVITY_REORDER_TO_FRONT

就按在Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT最后说的,如果在A,B,C,D正常启动的话,不管B有没有用FLAG_ACTIVITY_BROUGHT_TO_FRONT启动,此时在D中启动B的话,还是会变成A,C,D,B的。

FLAG_ACTIVITY_NO_HISTORY

用这个标记顾名思义! 意思就是说用这个FLAG启动的Activity,一旦推出,他就不会存在于栈中,比方说!原来是A,B,C 这个时候再C中以这个FLAG启动D的,D再启动E,这个时候栈中情况为A,B,C,E。







更多相关文章

  1. 深入Android【四】—— 组件调用
  2. JNI之一:基础 && JAVA调用win dll实例
  3. MVP 模式在 Android(安卓)中的使用
  4. Android(安卓)Activity中的四种启动模式
  5. Android(安卓)MVP设计模式实例详解
  6. 【React Native开发】React Native For Android环境配置以及第一
  7. Android(安卓)解决多个Fragment切换时不断实例化
  8. android EditText inputAction后键盘保留和收起问题
  9. Andorid中的Spinner编写实例

随机推荐

  1. Android高手进阶教程(十一)之----Android
  2. Android应用程序的生命周期
  3. Android(安卓)Things:你应该了解的Android
  4. Android(安卓)Relative Layout 安卓相对
  5. Andriod是什么?
  6. android surfaceflinger研究----Surface
  7. android国际化
  8. 《第一行代码--Android》读书笔记之多线
  9. Android开机启动Activity或者Service方法
  10. Android中JNI编程的那些事儿 【转】