androidActivity相关属性和 启动模式Task taskAffinity 说明

 manifest文件中,activity的属性配置说明


       description:说明:

       声明一个activity(一个Activity子类),它实现了应用程序的可视界面的一部分。所有activity都必须用manifest文件的元素声明。系统将无法看到任何没有被声明的activity,也就无法运行之。

       attributes:属性:

       activity是否可以从启动它的task移动到之后被带到前台的跟它有affinity的task里 — “true”表示它可以被移动,”false”表示它必须留在启动它的task里。
       如果该属性未设置,元素对应的allowTaskReparenting属性值将适用于该activity。默认值是”false”。

       通常当一个activity开始后,它与启动它的activity的task相关联,并且整个生命周期都留在那里。你可以利用本属性在当前task 不再被显示时,将它强制重定位到跟它有affinity的task里。通常,它用来促使一个应用程序的activity移动到与那个应用程序关联的主 task里去。

       例如,如果一个e-mail信息包含一个到某网页的链接,点击该链接生成能显示该页面的一个activity。那个activity由浏览器应用程序定义,但是被作为一个e-mail task的一部分加载进来。如果它被重定位到浏览器task,在那个浏览器之后来到前台时它将被显示,并且当e-mail task重新来到前台时不再被显示。

       activity的affinity由taskAffinity属性定义。一个task的affinity决定于它的根activity的 affinity。因此,理所当然的,一个根activity总是在一个task里,带有相同的affinity。因为”singleTask” 或”singleInstance”载入模式的activity只能够在某个task的根部,重定父级仅仅适用于”standard” 和”singleTop”模式。(参照launchMode属性。)

       系统是否将总是维护该activity所在task的状态 — “true”表示将会这样,”false”表示允许系统在某些情况下重新设置该task到它的初始状态。默认值是”false”。该属性值只对task的根activity有意义;对于其他activity将被忽略。
       通常,系统当用户在主屏幕上重选该task的特定情况下清空一个task(移除stack里根activity上面的所有activity)。通常,出现这种情况是在用户超过了某个特定的时间间隔仍然没有访问该task,例如30分钟。

       然而,当本属性为”true”时,用户将总是回到该task的最新状态,无论他们怎么过去的。这个很有用,例如,在一个类似网络浏览器的应用程序里,这儿有许多用户不愿失去的状态(比如打开的复数的标签页)。

       android:clearTaskOnLaunch 载入时清空task

       当任何时候从主页屏幕重新载入时,是否移除task里除了根activity的所有activity — “true”表示该task总是被拆分至根activity,”false”表示不是。默认值为”false”。本属性只对开始一个新task的 activity(根activity)有意义;对于task里的其他activity将被忽略。

       假如,某人从主页屏幕载入activity P,并从那儿到达activity Q。用户接下来按了HOME键,然后返回到activity P。通常,用户将看到activity Q,因为那时他在P的task里操作的地方。然而,如果P将该标志设为”true”,当用户按了HOME键,该task进到后台去的时候,其上的所有的 activity(Q也属于这种情况)将被移除。所以以后回到该task时看到的只有P。

       如果本属性和allowTaskReparenting都是”true”,任何能够被重定父级的activity都将移动到那个跟它有同一affinity的task里去;接着如上所述,剩下的activity将被丢弃。

       android:configChanges 配置变更

       列举activity自己将处理的配置变更。当没有被列举的变更发生时,该activity将关闭并重启。当被列举的变更发生时,该activity将继续运行并调用它的onConfigurationChanged()方法。

       下面列举的任何或所有的字符串能够被用来设置本属性。值用’|'分隔 — 例如,”locale|navigation|orientation”。

<activity android:allowTaskReparenting=["true" | "false"]
android:alwaysRetainTaskState=["true" | "false"]
android:clearTaskOnLaunch=["true"" | "false"]
android:configChanges=[one or more of: "mcc" "mnc" "locale"
"touchscreen" "keyboard" "keyboardHidden"
"navigation" "orientation" "fontScale"]
android:enabled=["true" | "false"]
android:excludeFromRecents=["true" | "false"]
android:exported=["true" | "false"]
android:finishOnTaskLaunch=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:launchMode=["multiple" | "singleTop" |
"singleTask" | "singleInstance"]
android:multiprocess=["true" | "false"]
android:name="string"
android:noHistory=["true" | "false"] 
android:permission="string"
android:process="string"
android:screenOrientation=["unspecified" | "user" | "behind" |"landscape" | "portrait" |"sensor" | "nonsensor"]
android:stateNotNeeded=["true" | "false"]
android:taskAffinity="string"
android:theme="resource or theme"
android:windowSoftInputMode=[one or more of: "stateUnspecified"
"stateUnchanged" "stateHidden"
"stateAlwaysHidden" "stateVisible"
"stateAlwaysVisible" "adjustUnspecified"
"adjustResize" "adjustPan"] > 
. . .
</activity>

Activity的LaunchMode和taskAffinity

设置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文件中设置

1 <activity android:name=".activity.ActivityA"
2         android:launchMode="standard">
3     <intent-filter>
4         <action android:name="android.intent.action.MAIN" />
5             <category android:name="android.intent.category.LAUNCHER" />
6     </intent-filter>
7 </activity>

    2.  使用Intent flags设置 
1 Intent intent = new Intent();
2 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3 intent.setClass(ActivityA.this, ActivityB.class);
4 startActivity(intent);

 四种LaunchMode说明

  standard

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

1 //ActivityA.java
2 Intent intent = new Intent();
3 intent.setClass(ActivityA.this, ActivityB.class);
4 startActivity(intent);
5
6 //ActivityB.java
7 Intent intent = new Intent();
8 intent.setClass(ActivityB.this, ActivityA.class);
9 startActivity(intent);

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

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

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

singleTop

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

01 <code>//ActivityA.java
02 Intent intent = new Intent();
03 intent.setClass(ActivityA.this, ActivityA.class);
04 startActivity(intent);
05
06 @Override
07 protected void onNewIntent(Intent intent) {
08     logger.d("onNewIntent " + this.hashCode() + " taskID "
09                 + this.getTaskId());
10     super.onNewIntent(intent);
11 }

1 <activity android:name=".activity.ActivityA" android:label="ActivityA"
2             android:launchMode="singleTop">
3     <intent-filter>
4         <action android:name="android.intent.action.MAIN" />
5         <category android:name="android.intent.category.LAUNCHER" />
6     </intent-filter>
7 </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实例同时存在。

01 <code><activity android:name=".activity.ActivityA" android:label="ActivityA"android:launchMode="standard">
02   <intent-filter>
03      <action android:name="android.intent.action.MAIN" />
04       <category android:name="android.intent.category.LAUNCHER" />
05   </intent-filter>
06 </activity>
07 <activity android:name=".activity.ActivityB" android:label="ActivityB"android:launchMode="singleTask">
08   <intent-filter>
09      <action android:name="android.intent.action.MAIN" />
10     </intent-filter>
11 </activity>
12 <activity android:name=".activity.ActivityC" android:label="ActivityC"android:launchMode="standard">
13   <intent-filter>
14      <action android:name="android.intent.action.MAIN" />
15     </intent-filter>
16 </activity></code>

 操作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。

01 <activity android:name=".activity.ActivityA" android:launchMode="singleTask">
02   <intent-filter>
03       <action android:name="android.intent.action.MAIN" />
04       <category android:name="android.intent.category.LAUNCHER" />
05   </intent-filter>
06 </activity>
07 <activity android:name=".activity.ActivityB" android:launchMode="singleInstance">
08   <intent-filter>
09      <action android:name="android.intent.action.MAIN" />
10   </intent-filter>
11 </activity>
12 <activity android:name=".activity.ActivityC">
13   <intent-filter>
14      <action android:name="android.intent.action.MAIN" />
15    </intent-filter>
16 </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的表现:

  • 当运行一个activity包含了FLAG_ACTIVITY_NEW_TASK标记
    1 //ActivityA.java
    2 Intent intent = new Intent();   
    3 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    4 intent.setClass(ActivityA.this, ActivityB.class);
    5 startActivity(intent);

    01 <activity android:name=".activity.ActivityA"android:taskAffinity="com.android.demo.affinity1">
    02   <intent-filter>
    03      <action android:name="android.intent.action.MAIN" />
    04        <category android:name="android.intent.category.LAUNCHER" />
    05     </intent-filter>
    06 </activity>
    07 <activity android:name=".activity.ActivityB"android:taskAffinity="com.android.demo.affinity2">
    08   <intent-filter>
    09      <action android:name="android.intent.action.MAIN" />
    10    </intent-filter>
    11 </activity>

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

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

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

    01 <activity android:name=".activity.ActivityA"android:taskAffinity="com.android.demo.affinity1">
    02   <intent-filter>
    03      <action android:name="android.intent.action.MAIN" />
    04        <category android:name="android.intent.category.LAUNCHER" />
    05     </intent-filter>
    06 </activity>
    07 <activity android:name=".activity.ActivityB"android:taskAffinity="com.android.demo.affinity2">
    08   <intent-filter>
    09      <action android:name="android.intent.action.MAIN" />
    10    </intent-filter>
    11 </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。

    01 //Demo1
    02 //ActivityA.java
    03 Intent intent = new Intent();
    04 intent.setClass(ActivityA.this, ActivityC.class);
    05 startActivity(intent);
    06
    07 //ActivityC.java
    08 tv.setText(ActivityC.this.toString());
    09
    10 //Demo2
    11 //ActivityB.java
    12 Intent intent = new Intent();
    13 intent.setClassName("com.android.demo","com.android.demo.activity.ActivityC");
    14 ActivityB.this.startActivity(intent);

    01 //Demo1
    02 <activity android:name=".activity.ActivityA">
    03   <intent-filter>
    04     <action android:name="android.intent.action.MAIN" />
    05     <category android:name="android.intent.category.LAUNCHER" />
    06   </intent-filter>
    07 </activity>
    08 <activity android:name=".activity.ActivityC" android:allowTaskReparenting="true">
    09   <intent-filter>
    10     <action android:name="android.intent.action.MAIN" />
    11   </intent-filter>
    12 </activity>
    13
    14
    15 //Demo2
    16 <activity android:name=".ActivityB">
    17   <intent-filter>
    18     <action android:name="android.intent.action.MAIN" />
    19     <category android:name="android.intent.category.LAUNCHER" />
    20   </intent-filter>
    21 </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。

    1 //Demo1
    2 <activity android:name=".activity.ActivityC"
    3             android:taskAffinity="com.android.demo.activityc"
    4             android:allowTaskReparenting="true">
    5   <intent-filter>
    6     <action android:name="android.intent.action.MAIN" />
    7   </intent-filter>
    8 </activity>

     运行结果:

      

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

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

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

    01 //Demo2
    02 <activity android:name=".ActivityB" android:taskAffinity="com.android.demo.activityc">
    03   <intent-filter>
    04     <action android:name="android.intent.action.MAIN" />
    05     <category android:name="android.intent.category.LAUNCHER" />
    06   </intent-filter>
    07 </activity>
    08
    09 //Demo1
    10 <activity android:name=".activity.ActivityC"
    11             android:taskAffinity="com.android.demo.activityc"
    12             android:allowTaskReparenting="true">
    13   <intent-filter>
    14     <action android:name="android.intent.action.MAIN" />
    15   </intent-filter>
    16 </activity>

     运行结果:

      

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

 设置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文件中设置

1 <activity android:name=".activity.ActivityA"
2         android:launchMode="standard">
3     <intent-filter>
4         <action android:name="android.intent.action.MAIN" />
5             <category android:name="android.intent.category.LAUNCHER" />
6     </intent-filter>
7 </activity>

    2.  使用Intent flags设置 
1 Intent intent = new Intent();
2 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3 intent.setClass(ActivityA.this, ActivityB.class);
4 startActivity(intent);

 四种LaunchMode说明

  standard

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

1 //ActivityA.java
2 Intent intent = new Intent();
3 intent.setClass(ActivityA.this, ActivityB.class);
4 startActivity(intent);
5
6 //ActivityB.java
7 Intent intent = new Intent();
8 intent.setClass(ActivityB.this, ActivityA.class);
9 startActivity(intent);

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

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

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

singleTop

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

01 <code>//ActivityA.java
02 Intent intent = new Intent();
03 intent.setClass(ActivityA.this, ActivityA.class);
04 startActivity(intent);
05
06 @Override
07 protected void onNewIntent(Intent intent) {
08     logger.d("onNewIntent " + this.hashCode() + " taskID "
09                 + this.getTaskId());
10     super.onNewIntent(intent);
11 }

1 <activity android:name=".activity.ActivityA" android:label="ActivityA"
2             android:launchMode="singleTop">
3     <intent-filter>
4         <action android:name="android.intent.action.MAIN" />
5         <category android:name="android.intent.category.LAUNCHER" />
6     </intent-filter>
7 </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实例同时存在。

01 <code><activity android:name=".activity.ActivityA" android:label="ActivityA"android:launchMode="standard">
02   <intent-filter>
03      <action android:name="android.intent.action.MAIN" />
04       <category android:name="android.intent.category.LAUNCHER" />
05   </intent-filter>
06 </activity>
07 <activity android:name=".activity.ActivityB" android:label="ActivityB"android:launchMode="singleTask">
08   <intent-filter>
09      <action android:name="android.intent.action.MAIN" />
10     </intent-filter>
11 </activity>
12 <activity android:name=".activity.ActivityC" android:label="ActivityC"android:launchMode="standard">
13   <intent-filter>
14      <action android:name="android.intent.action.MAIN" />
15     </intent-filter>
16 </activity></code>

 操作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。

01 <activity android:name=".activity.ActivityA" android:launchMode="singleTask">
02   <intent-filter>
03       <action android:name="android.intent.action.MAIN" />
04       <category android:name="android.intent.category.LAUNCHER" />
05   </intent-filter>
06 </activity>
07 <activity android:name=".activity.ActivityB" android:launchMode="singleInstance">
08   <intent-filter>
09      <action android:name="android.intent.action.MAIN" />
10   </intent-filter>
11 </activity>
12 <activity android:name=".activity.ActivityC">
13   <intent-filter>
14      <action android:name="android.intent.action.MAIN" />
15    </intent-filter>
16 </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的表现:

  • 当运行一个activity包含了FLAG_ACTIVITY_NEW_TASK标记
    1 //ActivityA.java
    2 Intent intent = new Intent();   
    3 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    4 intent.setClass(ActivityA.this, ActivityB.class);
    5 startActivity(intent);

    01 <activity android:name=".activity.ActivityA"android:taskAffinity="com.android.demo.affinity1">
    02   <intent-filter>
    03      <action android:name="android.intent.action.MAIN" />
    04        <category android:name="android.intent.category.LAUNCHER" />
    05     </intent-filter>
    06 </activity>
    07 <activity android:name=".activity.ActivityB"android:taskAffinity="com.android.demo.affinity2">
    08   <intent-filter>
    09      <action android:name="android.intent.action.MAIN" />
    10    </intent-filter>
    11 </activity>

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

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

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

    01 <activity android:name=".activity.ActivityA"android:taskAffinity="com.android.demo.affinity1">
    02   <intent-filter>
    03      <action android:name="android.intent.action.MAIN" />
    04        <category android:name="android.intent.category.LAUNCHER" />
    05     </intent-filter>
    06 </activity>
    07 <activity android:name=".activity.ActivityB"android:taskAffinity="com.android.demo.affinity2">
    08   <intent-filter>
    09      <action android:name="android.intent.action.MAIN" />
    10    </intent-filter>
    11 </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。

    01 //Demo1
    02 //ActivityA.java
    03 Intent intent = new Intent();
    04 intent.setClass(ActivityA.this, ActivityC.class);
    05 startActivity(intent);
    06
    07 //ActivityC.java
    08 tv.setText(ActivityC.this.toString());
    09
    10 //Demo2
    11 //ActivityB.java
    12 Intent intent = new Intent();
    13 intent.setClassName("com.android.demo","com.android.demo.activity.ActivityC");
    14 ActivityB.this.startActivity(intent);

    01 //Demo1
    02 <activity android:name=".activity.ActivityA">
    03   <intent-filter>
    04     <action android:name="android.intent.action.MAIN" />
    05     <category android:name="android.intent.category.LAUNCHER" />
    06   </intent-filter>
    07 </activity>
    08 <activity android:name=".activity.ActivityC" android:allowTaskReparenting="true">
    09   <intent-filter>
    10     <action android:name="android.intent.action.MAIN" />
    11   </intent-filter>
    12 </activity>
    13
    14
    15 //Demo2
    16 <activity android:name=".ActivityB">
    17   <intent-filter>
    18     <action android:name="android.intent.action.MAIN" />
    19     <category android:name="android.intent.category.LAUNCHER" />
    20   </intent-filter>
    21 </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。

    1 //Demo1
    2 <activity android:name=".activity.ActivityC"
    3             android:taskAffinity="com.android.demo.activityc"
    4             android:allowTaskReparenting="true">
    5   <intent-filter>
    6     <action android:name="android.intent.action.MAIN" />
    7   </intent-filter>
    8 </activity>

     运行结果:

      

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

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

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

    01 //Demo2
    02 <activity android:name=".ActivityB" android:taskAffinity="com.android.demo.activityc">
    03   <intent-filter>
    04     <action android:name="android.intent.action.MAIN" />
    05     <category android:name="android.intent.category.LAUNCHER" />
    06   </intent-filter>
    07 </activity>
    08
    09 //Demo1
    10 <activity android:name=".activity.ActivityC"
    11             android:taskAffinity="com.android.demo.activityc"
    12             android:allowTaskReparenting="true">
    13   <intent-filter>
    14     <action android:name="android.intent.action.MAIN" />
    15   </intent-filter>
    16 </activity>

     运行结果:

      

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值