zoukankan      html  css  js  c++  java
  • Activity的LaunchMode和taskAffinity

    做项目到现在都一直没有理解LaunchMode有什么用,或许根本就没真正花心思去看,所以今天把这部分整理下。

      设置Activity的LaunchMode属性可以决定这个Activity是和当前Task保持关联,还是说每次运行这个Activity是新建一个实例,还是保持单例。

      Task和Back Stack简介

      task是一组Activities的集合,一组Activities被Stack(back stack)所管理。

      在一个应用中,有3个activities,分别是activity1,activity2,activity3,首先activity1被start,此时,如果应用没有创建task则创建,并把activity1压入栈顶,activity1触发onCreate->onStart->onResume。

      

      接着activity1转向到activity2时,activity1先触发onPause,activity2触发onCreate->onStart->onResume,然后activity1触发onPause->onStop,activity2压入栈顶。

      

      以此类推,activity2转向activity3也是一样的步骤。那么当前栈顶是activity3。

      

      当我们按下手机上的返回键时,栈顶的activity3触发onPause,activity2需要从状态stop到pause,所以触发了onPause->onStart->onResume,activity3触发onStop->onDestory,因为activity3从栈顶弹出,所以触发onDestory,此时,activity2在栈顶。

      back stack

      如果继续按返回键,当前栈顶的activity弹出并被destory,直到home界面。当所有的activity都弹出了,这个task也就消亡了。

      当开始一个新的task时,前一个task被设置为后台,在后台,所有的activity都处理stop状态,但是back stack保留了所有后台activity的状态信息,只是丢失了焦点。

    task

      反复的在两个activity之间切换,activity会产生多个独立的实例。

      stack

      查阅有关Activity生命周期更多说明。

      两种方式设置LaunchMode属性

      1.  在 manifest文件中设置

    复制代码
    <activity android:name=".activity.ActivityA"
            android:launchMode="standard">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    复制代码

      2.  使用Intent flags设置

    Intent intent = new Intent();
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setClass(ActivityA.this, ActivityB.class);
    startActivity(intent);

      四种LaunchMode说明

      standard

       不做任何设置,默认模式就是standard,activity在每次start时,都会有一个新的实例被task管理。下面看下代码实例。

    复制代码
    //ActivityA.java
    Intent intent = new Intent();
    intent.setClass(ActivityA.this, ActivityB.class);
    startActivity(intent);
    
    //ActivityB.java
    Intent intent = new Intent();
    intent.setClass(ActivityB.this, ActivityA.class);
    startActivity(intent);
    复制代码

     操作1:在ActivityA(蓝)和ActivityB(绿)之间重复切换,按返回键推到home界面。

      可以发现(蓝色86和绿色79的taskID)ActivityA和ActivityB都在同一个task,并且每次resume的实例都是不一样的。这说明在一个activity可以有多个实例在同一个task中。

      在按返回按键时,将依次弹出stack。

      singleTop

      和standard一样,可以多次实例,但,如果处于当前栈顶并且接受到一个与当前activity一样类型的intent,那么不会创建一个新实例,而是触发onNewIntent()事件。

    复制代码
    //ActivityA.java
    Intent intent = new Intent();
    intent.setClass(ActivityA.this, ActivityA.class);
    startActivity(intent);
    
    @Override
    protected void onNewIntent(Intent intent) {
        logger.d("onNewIntent " + this.hashCode() + " taskID "
                    + this.getTaskId());
        super.onNewIntent(intent);
    }
    复制代码
    复制代码
    <activity android:name=".activity.ActivityA" android:label="ActivityA"
                android:launchMode="singleTop">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    复制代码

    操作1:点击ActivityA上的按钮

      发现当点击按钮是ActivityA->onPause->onNewIntent->onResume,没有新建新的实例(蓝62)。

      这个模式在这个场景下比较有用,比如:如果有一个其他的应用想启动你的Activity(launch mode为singleTop),而你当前的Activity正好在栈顶,那么就会调用到onNewIntent方法。原文贴上:If an instance of the activity already exists at the top of the current task, the system routes the intent to that instance through a call to its onNewIntent() method。

      singleTask

      系统会创建一个新task(如果没有启动应用)和一个activity新实例在新task根部,然后,如果activity实例已经存在单独的task中,系统会调用已经存在activity的 onNewIntent()方法,而不是存在新实例,仅有一个activity实例同时存在。

    复制代码
    <activity android:name=".activity.ActivityA" android:label="ActivityA" android:launchMode="standard">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:name=".activity.ActivityB" android:label="ActivityB" android:launchMode="singleTask">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
        </intent-filter>
    </activity>
    <activity android:name=".activity.ActivityC" android:label="ActivityC" android:launchMode="standard">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
        </intent-filter>
    </activity>
    复制代码

     操作1:ActivityA->ActivityB->ActivityC->ActivityA->ActivityB->ActivityC

      

       可以看到,当再次进入ActivityB时,没有onCreate,而是onNewIntent(绿55)。

       这里我们也可以发现一个现象,当在调用到ActivityB的onNewIntent时,之前的ActivityA和ActivityC都调用了onDestory。也就是说,系统发现栈中存在ActivityB的实例时,ActivityA和ActivityB都弹栈了。

       列出Log日志(这里设ActivityA的LaunchMode为singleTask),ActivityB和ActivityC都在onNewIntent前后调用了onDestory。

      

      singleInstance

        和singleTask相似,除了系统不会让其他的activities运行在所有持有的task实例中,这个activity是独立的,并且task中的成员只有它,任何其他activities运行这个activity都将打开一个独立的task。

    复制代码
    <activity android:name=".activity.ActivityA" android:launchMode="singleTask">
      <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:name=".activity.ActivityB" android:launchMode="singleInstance">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
      </intent-filter>
    </activity>
    <activity android:name=".activity.ActivityC">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
       </intent-filter>
    </activity>
    复制代码

     操作1:ActivityA->ActivityB->ActivityA

      

      可以发现,两个Activity是在不同的Task中,其次,当调用到onNewIntent时,ActivityB没有被Destory,互不干涉。

      操作2:ActivityA->ActivityB->ActivityC,按返回键

      

      图解:

      

      刚进入应用,创建TaskA,ActivityA为栈顶,从ActivityA到ActivityB,ActivityB进入TaskB(如果再次进入ActivityB,则不创建Task,调用onNewIntent),此时TaskB中的ActivityB为栈顶,从ActitivyB到ActivityC,ActivityC为栈顶。

      一直按返回键,先从TaskA中依次将Activity弹出,然后再从TaskB中将ActiviyB弹出。ActiviyC->ActivityA->ActivityB。

      这里分析一个问题,浏览器的LaunchMode为singleTask,所以如果当你点击一个连接下载文件时(由一个activity来处理下载,launchmode为standard),如果再次进入浏览器,那么下载页面就被Destory了,那么这里我们可以把下载页面LaunchMode设置为singleInstance可以解决这个问题。

      Affinity定义

      Affinity更像是表明了activity属于哪个task,默认情况下,应用所有的activities都有相同的affinity,所以都是在相同的task中。然后你可以编辑默认的affinity。Activities定义在不同的应用可以共享一个affinity,或者activities定义在相同的应用中可以被不同的affinities所关联。

      你可以编辑在<activity>元素中activity的taskAffinity属性。

       先看看两种不同的情况下affinity的表现:

    //ActivityA.java
    Intent intent = new Intent();    
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setClass(ActivityA.this, ActivityB.class); startActivity(intent);
    复制代码
    <activity android:name=".activity.ActivityA" android:taskAffinity="com.android.demo.affinity1">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name=".activity.ActivityB" android:taskAffinity="com.android.demo.affinity2">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
       </intent-filter>
    </activity>
    复制代码

    操作1:不同的affinity值,ActivityA->ActivityB

    如果已经存在相同affinity,那么新activity运行在这个task中,否则,系统创建新task。

    操作2:相同的affinity值,ActivityA->ActivityB

    复制代码
    <activity android:name=".activity.ActivityA" android:taskAffinity="com.android.demo.affinity1">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name=".activity.ActivityB" android:taskAffinity="com.android.demo.affinity2">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
       </intent-filter>
    </activity>
    复制代码

    可以看出ActivityA和ActivityB都运行在同一个task中。

      使用来表示是否允许activity重新附属其他Task,还是举例说明吧。

      有两个应用,Demo1和Demo2,Demo1中有2个Activity(ActivityA,ActivityC),ActivityA可以转向到ActivityC,Demo2中有一个Activity(ActivityB),也可以转向到ActivityC。

      操作1:设置ActivityC的allowTaskReparenting属性为true。

          运行Demo2,转向到ActivityC,在ActivityC中打印信息,返回到HOME界面,运行Demo1。

    复制代码
    //Demo1 
    //ActivityA.java
    Intent intent = new Intent();
    intent.setClass(ActivityA.this, ActivityC.class);
    startActivity(intent);
    
    //ActivityC.java
    tv.setText(ActivityC.this.toString());
    
    //Demo2
    //ActivityB.java
    Intent intent = new Intent();
    intent.setClassName("com.android.demo","com.android.demo.activity.ActivityC");
    ActivityB.this.startActivity(intent);
    复制代码
    复制代码
    //Demo1
    <activity android:name=".activity.ActivityA">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:name=".activity.ActivityC" android:allowTaskReparenting="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
      </intent-filter>
    </activity>

    //Demo2 <activity android:name=".ActivityB">   <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    复制代码

     运行结果:(黄色Demo1,绿色Demo2)

      

        ActivityB转向到ActivityC,此时ActivityC就关联到Demo2的Task中,TaskID都为231。在运行Demo1时,看到是ActivityC而不是ActivityA。当再次进入Demo2时就看不到ActivityC了。

      操作2:将ActivityC的taskAffinity设置为"com.android.demo.activityc"。

          运行Demo2,转向到ActivityC,在ActivityC中打印信息,返回到HOME界面,运行Demo1。

    复制代码
    //Demo1
    <activity android:name=".activity.ActivityC"
                android:taskAffinity="com.android.demo.activityc"
                android:allowTaskReparenting="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
      </intent-filter>
    </activity>
    复制代码

     运行结果:

      

       从结果中可以看出,Demo1和Demo2都拥有ActivityC,也就是说有2个Task里存在ActivityC,分别被Demo1和Demo2所使用。

      操作3:将ActivityC和ActivityB的taskAffinity都设为"com.android.demo.activityc"。

          运行Demo2,转向到ActivityC,在ActivityC中打印信息,返回到HOME界面,运行Demo1。

    复制代码
    //Demo2
    <activity android:name=".ActivityB" android:taskAffinity="com.android.demo.activityc">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    
    //Demo1
    <activity android:name=".activity.ActivityC"
                android:taskAffinity="com.android.demo.activityc"
                android:allowTaskReparenting="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
      </intent-filter>
    </activity>
    复制代码

      运行结果:

      

       和操作1相反,再进入Demo2时看到是ActivityC,进入Demo1都是看到ActivityA。

      写到最后越来越崩溃了,如果有什么地方写的不对或不清楚请指明。

      转帖请说明原文出处:http://www.cnblogs.com/SteveMing/archive/2012/04/24/2459575.html 

  • 相关阅读:
    085 Maximal Rectangle 最大矩形
    084 Largest Rectangle in Histogram 柱状图中最大的矩形
    083 Remove Duplicates from Sorted List 有序链表中删除重复的结点
    082 Remove Duplicates from Sorted List II 有序的链表删除重复的结点 II
    081 Search in Rotated Sorted Array II 搜索旋转排序数组 ||
    080 Remove Duplicates from Sorted Array II 从排序阵列中删除重复 II
    079 Word Search 单词搜索
    078 Subsets 子集
    bzoj2326: [HNOI2011]数学作业
    bzoj2152: 聪聪可可
  • 原文地址:https://www.cnblogs.com/veins/p/3975079.html
Copyright © 2011-2022 走看看