关闭

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

标签: androidActivity启动模式TaskInstance
136人阅读 评论(0) 收藏 举报
分类:


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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3473次
    • 积分:92
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档