actvity 的启动模式为四种
standard
singleTop
singleTask
singleInstance
/**
* 一个任务由多个相关联的Activity实例构成
* 一个任务对应一个回退栈
* 同一个任务中的Activity实例位于同一个回退栈中
* Activity实例没有了则任务也不存在了
* Activity实例 是按照被启动的顺序入栈的
* Activity实例在栈中的顺序是不会改变的
* 位于栈顶的的Activity实例就是当前可以和用户交互的Activity实例
* 默认情况下使用 Intent启动一个Activity 都是创建该Activity的一个新的实例
*
*/
下面在代码中 详细介绍 四种启动模式
创建四个Activity 分别使用四种启动模式,Activity 的代码都是相同的 名称不同而已,不再一一粘贴,自行更换类名
public class MAStandard extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ma_standard);
TextView textView = (TextView) findViewById(R.id.txt_startmodel_infoid);
textView.setText("this " + this.toString() + "\n" + "\n" + this.getTaskId());
}
//跳转到A standtard activity
public void toMAStandard(View view) {
startActivity(new Intent(this, MAStandard.class));
}
//跳转到b top activity
public void toMBTop(View view) {
startActivity(new Intent(this, MBTop.class));
}
//跳转到C TASK activity
public void toMCTask(View view) {
startActivity(new Intent(this, MCTask.class));
}
//跳转到A Instance activity
public void toMDInstance(View view) {
startActivity(new Intent(this, MDInstance.class));
}
}
配置文件中 配置其 启动模式
//----------启动模式 使用的activity------------
<activity
android:name=".activitystartmodel.MAStandard"
android:label="@string/title_activity_standard"
android:theme="@android:style/Theme.Holo" >
</activity>
<activity
android:launchMode="singleTop"
android:name=".activitystartmodel.MBTop"
android:label="@string/title_activity_top_b"
android:theme="@android:style/Theme.Holo" >
</activity>
<activity
android:launchMode="singleTask"
android:name=".activitystartmodel.MCTask"
android:label="@string/title_activity_task_c"
android:theme="@android:style/Theme.Holo" >
</activity>
<activity
android:launchMode="singleInstance"
android:name=".activitystartmodel.MDInstance"
android:label="@string/title_activity_instance_d"
android:theme="@android:style/Theme.Holo" >
</activity>
//----------启动模式 使用的activity----------------
简单介绍一下
/**
* 这4中模式又分两类,standard和signleTop属于一类,singleTask和signleInstance属于另一类。
* standard和singleTop属性的 Activity 的实例可以属于任何任务(Task), 并且可以位于Activity堆栈的任何位置。
* 比较典型的一种情况是,一个任务的代码执行startActivity(),
* 如果传递的 Intent 对象没有包含 FLAG_ACTIVITY_NEW_TASK 属性, 指定的 Activity 将被该任务调用,从而装入该任务的Activity 堆栈中。<span style="font-size:14px;">(参考:</span><pre name="code" class="java"><h1><span style="font-size:14px;">Task 与Activity 的详解 http://blog.youkuaiyun.com/mayingcai1987/article/details/6200909)</span>
</h1>
*
* standard和singleTop的区别在于:
*standard模式的Activity在被调用时会创建一个新的实例,所有实例处理同一个Intent对象;
<h2><pre name="code" class="java"><span style="font-size:12px;"> * 启动模式是SingleTop:如果一个Activity的启动模式是SingleTop,而且位于回退栈的栈顶,那么再次启动该
* Activity时,不会创建新的实例,直接使用栈顶的实例,会去回调onNewIntent()方法
*
* 如果一个Activity的启动模式是SingleTop但是不位于栈顶,那么还会创建新的实例</span>
* * singleTask 和 singleInstance模式的Activity 仅可用于启动任务的情况, * 这种模式的Activity总是处在Activity堆栈的最底端,(说法错误 后面 见 task启动模式介绍) * 并且一个任务中只能被实例化一次。 * * 两者的区别在于:对于 singleInstance模式的Activity, * 任务的Activity堆栈中如果有这样的Activity,那它将是堆栈中的唯一的 Activity, 当前任务收到的 Intent 都由它处理, * 由它开启的其他 Activity 将在其他任务中被启动; 对于 SingleTask模式的Activity,它在堆栈底端,其上方可以有其他Activity被创建, * 但是,如果发给该Activity的Intent对象到来时该Activity不在堆栈顶端,那么该Intent对象将被丢弃, * 但是界面还是会切换到当前的Activity。 * * @author cfg-m
*/
Standard 和singleTop 比较简单不再详细介绍 重点介绍 剩下两种
/**
*
* SingleTask:只有一个实例,它允许其它的 activity位于同一个任务中,(位于同一个任务中的activity
* 就位于同一个回退栈中),当已经存在该启动模式的 actiivty的实例,
* 又再次启动时,使用已经存在的实例,但是会把位于该实例之上的所有的Activity实例销毁掉
* 既使 此activity 成为栈顶 在此之上的activity 全部销毁掉
*/
/**
*
* 关于singleTask这个 颇为迷惑
* google api说singTask模式只能启动一个task,且总是位于栈底,这个也不是完全正确
* 正解: 1.singleTask 并不一定处于栈底
* 2.singleTask 并一定会是栈底的根元素
* 3.singleTask 并不一定会启动新的task
*
* 1、如果在同一个应用(apk)中使用singleTask,刚不在栈底,对应于下面的情况一
*
* 2、如果从不同应用启动一个singleTask的activity,刚依赖于此activity所在的栈,如果之前没有运行过,
* 则新建栈处于栈底,如果有运行过,则有可能不在栈底,对应于情况二
*
* 情况一:如果在本程序中启动singleTask的activity:假设ActivityA是程序的入口,是默认的模式(standard),
* ActivityB是singleTask 模式,由ActivityA启动,刚ActivityB不会位于栈底,不是根元素,不会启动新的task,
* 此种情况ActivityB会和ActivityA在一个栈中,位于ActivityA上面
*
* 情况二:如果ActivityB由另外一个程序启动:假设apkA是情况一中的应用,apkB是另外一个测试程序,在apkB中启动apkA中的ActivityB,
* 再分两种情况,如果ActivityB未启动过,刚ActivityB会位于栈底,是根元素,会启动新的task;如果ActivityB启动过,则ActivityB保持原来的位置不变,
* 在栈底或者栈顶,移除掉ActivityB之上所有的activity(如果有)
*
*
*
*/
taskAffinity介绍
/******
每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明该Activity的taskAffinity,
那么它的这个属性就等于Application指明的taskAffinity,如果Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,
它的值等于它的根Activity的taskAffinity的值。
一开始,创建的Activity都会在创建它的Task中,并且大部分都在这里度过了它的整个生命。然而有一些情况,
创建的Activity会被分配其它的Task中去,有的甚至,本来在一个Task中,之后出现了转移。我们首先分析一下android文档给我们介绍的两种情况。
第一种情况。如果该Activity的allowTaskReparenting设置为true,
它进入后台,当一个和它有相同affinity的Task进入前台时,它会重新宿主,进入到该前台的task中。
我们验证一下这种情况。
Application Activity taskAffinity allowTaskReparenting
application1 Activity1 com.winuxxan.affinity true
application2 Activity2 com.winuxxan.affinity false
我们创建两个工程,application1和application2,
分别含有Activity1和Activity2,它们的taskAffinity相同,Activity1的allowTaskReparenting为true。
首先,我们启动application1,加载Activity1,然后按Home键,使该task(假设为task1)进入后台。然后启动application2,默认加载Activity2。
我们看到了什么现象?没错,本来应该是显示Activity2,但是我们却看到了Activity1。实际上Activity2也被加载了,只是Activity1重新宿主,所以看到了Activity1。
第二种情况。如果加载某个Activity的intent,Flag被设置成FLAG_ACTIVITY_NEW_TASK时,它会首先检查是否存在与自己taskAffinity相同的Task,
如果存在,那么它会直接宿主到该Task中,如果不存在则重新创建Task。
*/
allowTaskReparenting 介绍
/***** allowTaskReparenting用于配置是否允许该activity可以更换从属task,通常情况二者连在一起使用,用于实现把一个应用程序的Activity移到另一个应用程序的Task中。
allowTaskReparenting用来标记Activity能否从启动的Task移动到taskAffinity指定的Task,默认是继承至application中的allowTaskReparenting=false,如果为true,则表示可以更换;false表示不可以。
<p>引用网上的解释例子:</p> 一般来说,当Activity启动后,它就与启动它的Task关联,并且在那里耗尽它的整个生命周期。当当前的Task不再显示时,你可以使用这个特性来强制Activity移动到有着affinity的Task中。
例如,如果e-mail中包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序定义的,但是,现在它作为e-mail Task的一部分。如果它重新宿主到Browser Task里,
当Browser下一次进入到前台时,它就能被看见,并且,当e-mail Task再次进入前台时,就看不到它了。
*/
SingleInstance 介绍
/*******
* SingleInstance:只有一个实例,它不允许其它的 activity位于同一个任务中,
* 当已经存在该启动模式的 activity的实例,又再次启动时,使用已经存在的实例
* 它不允许其它的 activity位于同一个任务中 指的使用新创建 一个 栈
*
* singleInstance 模式应该算是四种启动模式中最特殊也最复杂的一个了,多花点来理解这个模式。
* 不同于以上三种启动模式,
* 指定为 singleInstance 模式的活动会启用一个新的返回栈来管理这个活动
* (其实如果 singleTask 模式指定了不同的 taskAffinity,也会启动一个新的返回栈)。
*
* 每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。
* 如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,
* 如果 Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,
* 它的值等于它的根 Activity的taskAffinity的值
*
*LaunchMode=""SingleTask"
* taskAffinity="com.tencent.mm"(com.tencent.mm是借助于工具找到的微信包名),
* 就是把自己的Activity放到微信默认的Task栈里面,这样回退时就会遵循“Task只要有Activity一定从本Task剩余Activity回退"的原则,
* 不会回到自己的客户端;而且也不会影响自己客户端本来的Activity和Task逻辑。
*
*
*
* 意义:想象以下场景,假设我们的程序中有一个活动是允许其他程序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,
*
* 实现:使用前面三种启动模式肯定是做不到的,因为每个应用程序都会有自
* 己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。而使用
* singleInstance 模式就可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,
* 不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题。
* 问题: 好了,现在有一个问题就是这时这种情况下如果用户点击了Home键,
* 则再也回不到D的即时界面了。如果想解决这个问题,可以为D在Manifest.xml文件中的声明加上:
* <intent-filter>
* <action android:name="android.intent.action.MAIN" />
* <category android:name="android.intent.category.LAUNCHER" />
* </intent-filter>
* 加上这段之后,也就是说该程序中有两个这种声明,另一个就是那个正常的根activity,
* 在打成apk包安装之后,在程序列表中能看到两个图标,但是如果都运行的话,在任务管理器中其实也只有一个。
* 上面的情况点击D的那个图标就能回到它的即时界面(比如一个EditText,以前输入的内容,现在回到之后依然存在)。
* PS:intent-filter中
* <action android:name="android.intent.action.MAIN" />
* 和 <category android:name="android.intent.category.LAUNCHER" />
* 两个过滤条件缺一不可才会在程序列表中添加一个图标,
* 图标下的显示文字是android:label设定的字符串。
*/