Android 之Activity启动模式(一)之 lauchMode
2015-10-14 16:14
561 查看
launchMode简介
在讲解launchMode之前,需要先了解两个概念:task和taskAffinity。task是一个"First In Last Out"的栈,task可以有一个或多个Activity。我们可以将task看作是管理Activity的单元。某一时刻,系统可以有多个task;每个task可以有一个或多个Activity。同一个Activity可能只允许存在一个实例,也可能可以有多个实例,而且这些实例既可以位于同一个task,也可以位于不同的task。Activity究竟是怎么处理它的实例,以及它在task中的分布情况;这些都可以通过launchMode进行设置。
android:taskAffinity是Activity的一个属性。例如,android:taskAffinity="string"。它的作用是描述了不同Activity之间的亲密关系。拥有相同的taskAffinity的Activity是亲密的,它们之间在相互跳转时,会位于同一个task中,而不会新建一个task!
如果在manifest中没有对Activity的android:taskAffinity进行配置,则每个Activity都采用和Application相同的taskAffinity;这也就意味着,同一个Application中的所有Activity的taskAffinity在默认情况下是相同的!
下面开始介绍四种launchMode模式,在通过示例介绍之后,再来对这四种launchMode进行总结。
1. standard模式
standard模式是默认模式。在该模式下,Activity可以拥有多个实例,并且这些实例既可以位于同一个task,也可以位于不同的task。下面通过示例来对standard进行验证。在该示例中,ActivityTest是standard模式的,而且点击ActivityTest中的按钮能跳转到它自身。
点击查看:standard模式的测试源码
manifest源码
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher"> <activity android:name="ActivityTest" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
ActivityTest的代码
public class ActivityTest extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView tv = (TextView) findViewById(R.id.tv); tv.setText(this.toString()+", taskId="+this.getTaskId()); } public void onJump(View view) { Intent intent = new Intent(this, ActivityTest.class); startActivity(intent); } @Override protected void onNewIntent(Intent intent) { Log.d(TAG, "onNewIntent: intent="+intent); } }
说明:上面的ActivityTest就是android:launchMode="standard"模式的。onJump()是按钮的回调函数,点击该按钮,会重新创建一个ActivityTest实例。
测试内容:ActivityTest --> ActivityTest --> ActivityTest。 (注:ActivityTest --> ActivityTest表示从ActivityTest跳转到ActivityTest)
测试结果:每一个ActivityTest实例都是不同的,而且这三个ActivityTest实例都位于同一个task中。
结果分析:这与我们前面介绍的standard模式的特性是相符的。
2. singleTop模式
singleTop模式下,在同一个task中,如果存在该Activity的实例,并且该Activity实例位于栈顶(即,该Activity位于前端),则调用startActivity()时,不再创建该Activity的示例;而仅仅只是调用Activity的onNewIntent()。否则的话,则新建该Activity的实例,并将其置于栈顶。
2.1 singleTop示例一
点击查看:singleTop示例二的源码我们将"standard示例"中ActivityTest的launchMode修改为singleTop,其他的保持不变。修改后的manifest如下:
<activity android:name="ActivityTest" android:launchMode="singleTop" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>
说明:上面的ActivityTest就是android:launchMode="singleTop"模式的。并不会创建新的ActivityTest实例;但是会调用onNewIntent()。
测试内容:ActivityTest --> ActivityTest --> ActivityTest
测试结果:每一个ActivityTest实例都是相同的!当从一个ActivityTest跳转到它自身时,没有创建新的ActivityTest实例,但是会调用onNewIntent()。
结果分析:这与我们前面介绍的singleTop模式的特性是相符的。
如果是singleTop模式的Activity不在栈顶,那会如何呢?我们通过下面的示例来进行分析。
2.2 singleTop示例二
在该示例中,有两个Activity:ActivityTest和SecondActivity。其中ActivityTest是singleTop类型的,而SecondActivity则是standard类型的。这两个Activity之间能相互跳转。点击查看:singleTop示例二的源码
manifest的源码
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher"> <activity android:name="ActivityTest" android:launchMode="singleTop" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="SecondActivity" android:launchMode="standard"/> </application>
ActivityTest的代码
public class ActivityTest extends Activity { private static final String TAG="##ActivityTest##"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.d(TAG, "onCreate: "+this.toString()); TextView tv = (TextView) findViewById(R.id.tv); tv.setText(this.toString()); } public void onJump(View view) { Log.d(TAG, "onJump: "+this.toString()); Intent intent = new Intent(this, SecondActivity.class); startActivity(intent); } @Override protected void onNewIntent(Intent intent) { Log.d(TAG, "onNewIntent: intent="+intent+", activity="+this); } }
说明:上面的ActivityTest就是android:launchMode="singleTop"模式的。onJump()是按钮的回调函数,点击该按钮,会跳转到SecondActivity中。
public class SecondActivity extends Activity { private static final String TAG="##SecondActivity##"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second); Log.d(TAG, "onCreate: "+this.toString()); TextView tv = (TextView) findViewById(R.id.tv2); tv.setText(this.toString()); } public void onBack(View view) { Log.d(TAG, "onBack: "+this.toString()); Intent intent = new Intent(this, ActivityTest.class); startActivity(intent); } @Override protected void onNewIntent(Intent intent) { Log.d(TAG, "onNewIntent: intent="+intent+", activity="+this); } }
说明:上面的SecondActivity是standard模式的。onBack是按钮的回调函数,点击该按钮,会跳转回ActivityTest。
测试内容:ActivityTest --> SecondActivity --> ActivityTest
测试结果:两个ActivityTest是不同的实例!
结果分析:这与我们之前的描述是相符的,当singleTop类型的Activity不在栈顶时,会新建Activity实例。
4. singleTask模式
Google官网对singleTask的描述如下:The system creates a new task and instantiates the activity at the root of the new task. However, if an instance of the activity already exists in a separate task, the system routes the intent to the existing instance through a call to its onNewIntent() method,
rather than creating a new instance. Only one instance of the activity can exist at a time.
大致意思是:
在singleTask模式下,如果是第一次创建该Activity实例时,则会新建task并将该Activity添加到该task中。否则(该Activity的实例已存在),则会打开已有的Activity实例,并调用Activity的onNewIntent()方法,而不会新建Activity实例。在任意时刻,最多只会有该一个Activity实例存在。
上面的描述...其实特别抽象。我们通过实例来对singleTask进行了解,最后再对singleTask进行总结。需要建立的一个概念是:singleTask,顾名思义,只容许有一个包含该Activity实例的task存在!
4.1 singleTask示例一
点击查看:singleTask示例一的测试源码该示例是来验证:(01) 第一次创建singleTask类型的Activity时,会创建新的task!(02) 该Activity实例已经存在时,不会创建新的Activity实例,才是跳转到已有的Activity实例中。
将前面的"singleTop示例二"中的ActivityTest的模式改为"standard",将SecondActivity的模式改为"singleTask"。修改后的manifest如下:
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher"> <activity android:name="ActivityTest" android:launchMode="standard" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="SecondActivity" android:launchMode="singleTask" /> </application>
测试内容:ActivityTest --> SecondActivity --> ActivityTest --> SecondActivity
测试结果:(01) ActivityTest和SecondActivity在同一个task中。 (02) 两个SecondActivity是相同的实例!
结果分析:结论(01)验证失败,结论(02)验证成功!
为什么会出现结论(01)验证失败呢?根据Google官网的描述,分明会启动一个新的task才对啊?为什么呢?
会不会是由于ActivityTest和SecondActivity位于同一个APK中,由于它们的android:taskAffinity相同导致的!嗯...到底是不是呢?下面就通过示例来进一步验证!
4.2 singleTask示例二
点击查看:singleTask示例二的测试源码将"singleTask示例一"中的两个Activity的taskAffinity改为不同,其他保持不变。修改后的manifest如下:
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher"> <activity android:name="ActivityTest" android:launchMode="standard" android:taskAffinity="com.skw.activitytest.task01" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="SecondActivity" android:taskAffinity="com.skw.activitytest.task02" android:launchMode="singleTask" /> </application>
测试内容:ActivityTest --> SecondActivity --> ActivityTest --> SecondActivity
测试结果:(01) 第一个ActivityTest和第一个SecondActivity在不同task中。 (02) 两个SecondActivity是相同的实例!
结果分析:结论(01)验证成功,结论(02)验证成功!
进一步进行测试:ActivityTest --> SecondActivity --> ActivityTest --> SecondActivity --> 返回键 --> 返回键
测试结果:在前面测试的基础上,按两次返回键。结果:第一次按返回键的时候,回到第一次创建的ActivityTest实例;再按一次返回键的话,则返回到原始画面(第一次进入ActivityTest之前的画面)!
结果分析:这个结果表明,再次进入SecondActivity时,会将SecondActivity所在task中位于SecondActivity之上的全部Activity都删除!
总结来说:singleTask的结论与android:taskAffinity相关。以A启动B来说
(01) 当A和B的taskAffinity相同时:第一次创建B的实例时,并不会启动新的task,而是直接将B添加到A所在的task;否则,将B所在task中位于B之上的全部Activity都删除,然后跳转到B中。
(02) 当A和B的taskAffinity不同时:第一次创建B的实例时,会启动新的task,然后将B添加到新建的task中;否则,将B所在task中位于B之上的全部Activity都删除,然后跳转到B中。
5. singleInstance模式
singleInstance,顾名思义,是单一实例的意思,即任意时刻只允许存在唯一的Activity实例!根据Google官网的描述,在模式下,只允许有一个Activity实例。当第一次创建该Activity实例时,会新建一个task,并将该Activity添加到该task中。注意:该task只能容纳该Activity实例,不会再添加其他的Activity实例!如果该Activity实例已经存在于某个task,则直接跳转到该task。
5.1 singleInstance示例一
点击查看:singleInstance示例一的测试源码将前面的"singleTop示例二"中的ActivityTest的模式改为"standard",将SecondActivity的模式改为"singleInstance"。修改后的manifest如下:
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher"> <activity android:name="ActivityTest" android:launchMode="standard" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="SecondActivity" android:launchMode="singleInstance"/> </application>
测试内容:ActivityTest --> SecondActivity --> ActivityTest --> SecondActivity
测试结果:(01) 两个SecondActivity是同一个实例。 (02) 第一次进入的ActivityTest和第一次进入的SecondActivity位于不同的task中。 (03) 两个ActivityTest是位于同一个task中的不同实例。
结果分析:这个结论与预期是相同的,即,singleInstance类型的Activity的实例只能有一个,而且它只允许存在于单独的一个task中。singleInstance与相互跳转的两个Activity的taskAffinity无关系!
至于为什么两个ActivityTest是位于同一个task中的不同实例,那是因为它是standard类型的。我们可以将ActivityTest修改为singleTop等其他类型进行测试。
5.2 singleInstance示例二
点击查看:singleInstance示例二的测试源码将前面的"singleInstance示例一"中的ActivityTest的模式改为"singleTop"。修改后的manifest如下:
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher"> <activity android:name="ActivityTest" android:launchMode="singleTop" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="SecondActivity" android:launchMode="singleInstance"/> </application>
测试内容:ActivityTest --> SecondActivity --> ActivityTest --> SecondActivity
测试结果:(01) 两个SecondActivity是同一个实例。 (02) 第一次进入的ActivityTest和第一次进入的SecondActivity位于不同的task中。 (03) 两个ActivityTest是同一个实例。
结果分析:这个结论与预期是相同的。
launchMode模式总结
现在,总结一下launchMode的四种模式:
1. standard
它是默认模式。在该模式下,Activity可以拥有多个实例,并且这些实例既可以位于同一个task,也可以位于不同的task。
2.singleTop
该模式下,在同一个task中,如果存在该Activity的实例,并且该Activity实例位于栈顶(即,该Activity位于前端),则调用startActivity()时,不再创建该Activity的示例;而仅仅只是调用Activity的onNewIntent()。否则的话,则新建该Activity的实例,并将其置于栈顶。
3. singleTask
顾名思义,只容许有一个包含该Activity实例的task存在!总的来说:singleTask的结论与android:taskAffinity相关。以A启动B来说
(01) 当A和B的taskAffinity相同时:第一次创建B的实例时,并不会启动新的task,而是直接将B添加到A所在的task;否则,将B所在task中位于B之上的全部Activity都删除,然后跳转到B中。
(02) 当A和B的taskAffinity不同时:第一次创建B的实例时,会启动新的task,然后将B添加到新建的task中;否则,将B所在task中位于B之上的全部Activity都删除,然后跳转到B中。
4. singleInstance
顾名思义,是单一实例的意思,即任意时刻只允许存在唯一的Activity实例,而且该Activity所在的task不能容纳除该Activity之外的其他Activity实例!它与singleTask有相同之处,也有不同之处。
相同之处:任意时刻,最多只允许存在一个实例。
不同之处:(01) singleTask受android:taskAffinity属性的影响,而singleInstance不受android:taskAffinity的影响。 (02) singleTask所在的task中能有其它的Activity,而singleInstance的task中不能有其他Activity。 (03) 当跳转到singleTask类型的Activity,并且该Activity实例已经存在时,会删除该Activity所在task中位于该Activity之上的全部Activity实例;而跳转到singleInstance类型的Activity,并且该Activity已经存在时,不需要删除其他Activity,因为它所在的task只有该Activity唯一一个Activity实例。
相关文章推荐
- Android自定义控件开发系列(二)——带清除按钮的圆角输入框
- Android 倒计时的控制
- Android基础入门教程——8.2.2 Bitmap引起的OOM问题
- android spinner的使用
- android studio 用gradle 下载 jar 文件目录
- Android Dialog 禁止back键
- Android 四大组件(一)Activity
- 【Android学习总结】之Activity:初识Activity及使用
- 深入理解Android之Gradle
- Android游戏开发学习②焰火绽放效果实现方法
- Android SDK国内镜像
- 【Android学习总结】之Activity:初识Activity及使用
- UsbAccessory和UsbDevice的区别
- android ecilpse中使用color资源
- Android 长按Listview显示CheckBox,实现批量删除
- Android开发之隐式Intent中Intent-filter的三个属性-action,category,data
- 20.Android 设备工具DeviceUtil
- Android动画之三:Property Animation 完全解析 (上)
- Android自定义View(一)(验证码)
- 开启Material Design之旅——资源收集总结