深入贯彻落实 Activity 的四种启动模式

来源:互联网 发布:javascript用什么写的 编辑:程序博客网 时间:2024/06/04 18:26


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.csdn.net/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设定的字符串。 */




0 0