首页 > 代码库 > android当中taskAffinity属性与launchMode相关

android当中taskAffinity属性与launchMode相关

一、本文尝试解释以下问题

1.  Activity被启动之后放在哪个任务栈当中?与哪些因素有关?

2.  Activity的四种启动模式对Activity的启动有哪些影响?

3.  在Activity中使用startActivityForResult(intent, REQUESTCODE);和onActivityResult()

    是否与被启动的ActivitylaunchMode有关?如果有关,有什么关系?

二、Activity被启动之后放在哪个任务栈当中?与哪些因素有关?

1.基本论断:Activity启动之后对应的任务站与Activity的两个属性taskAffinityallowTask-

Reparenting有关

  2.原理

(1)任务栈的标识----任务栈名称的确定

    任务栈的标识是由任务栈的名称来确定的,例如,在通常情况下用包名标识一个唯一任务栈,清单文件如下:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.musictest01"

    android:versionCode="1"

    android:versionName="1.0" >

    <uses-sdk

        android:minSdkVersion="8"

        android:targetSdkVersion="17" />

    <application

        android:allowBackup="true"

        android:theme="@style/AppTheme" >

        <activity

            android:name="com.example.musictest01.MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

        <activity android:name=".AActivity"></activity>

        <activity android:name=".BActivity"></activity>

    </application>

</manifest>

     该文件当中<appliacation><activity>标签都没有设置taskAffinity属性,所以这个应用的默认任务栈名称就是包名"com.example.musictest01" , activity默认也会放入这个任务栈当中。

    <application>当中的属性android:taskAffinity指定该应用程序默认的任务栈名称,用来标识一个唯一的任务栈,如果不设置,则默认为包名

    <activity>当中的属性android:taskAffinity指定该activity的“宿主”任务栈名称

(2)情景分析:

第一步、定义宿主工程,其Manifest.xml文件如下:(ADT创建,不做任何修改)

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.master"

……>

    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme">

        <activity

            android:name="com.example.master.MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

</manifest>

第二步、定义奴隶工程,Manifest.xml如下(activityandroid:taskAffinity="com.example

.master")

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.slave"

    ……>

    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name="com.example.slave.MainActivity"

            android:label="@string/app_name"

            android:taskAffinity="com.example.master">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

        <activity

            android:name=".AActivity">

        </activity>

        <activity android:name=".BActivity">

        </activity>

    </application>

</manifest>

第三步、结果 

     当我们启动宿主工程,按home键将宿主任务栈放到后台,然后启动奴隶工程,神奇的事情发生了:奴隶工程的MainActivity并没有被加载,而是显示的是宿主工程的MainActivity

第四步、 同样道理,反过来执行,我们首先启动奴隶工程,MainActivity-->AActivity-->BActivity,home键,回到桌面启动宿主工程,结果并没有加载宿主工程的MainActivity,而是显示的是奴隶工程的BActivity.

第五步、结论

   android:taskAffinity="com.example.master" 此属性指定了该activity所在的任务栈名称,如果系统当中已经存在指定的任务栈,那么该activity启动的时候会重新寄宿到宿主当中(这是android的官方说明,但是在实际的实践中发现,启动该activity的时候仅仅是将指定的任务栈推到前台,显示该任务栈最顶端的那个原activity,本activity并没有被创建,换言之,该activity的生命周期的相关方法并没有被执行);

       如果系统当中没有指定的任务栈,那么系统会创建名为com.example.master 的任务栈,并将该activity放入到创建的任务栈当中。

第六步、诡异的事情:按照android官方文档的说明,宿主的activity当中应该要设置android:allow-

TaskReparenting="true",但是实验表明,不设置该属性亦可!

 

3. 与启动模式相结合的情景

3.1 android:taskAffinity FLAG_ACTIVITY_NEW_TASK结合

(1)基本论断

如果加载某个ActivityintentFlag被设置成FLAG_ACTIVITY_NEW_TASK时,它会首先检查是否存在与自己taskAffinity相同的Task,如果存在,那么它会直接宿主到该Task中,如果不存在则重新创建Task 

(2)测试。 
      
我们首先写一个应用,它有两个ActivityActivity1Activity2),AndroidManifest.xml如下: 

<application

android:icon="@drawable/icon" android:label="@string/app_name"> 
    <activity android:name=".Activity1" 
                  
android:taskAffinity="com.example.task" 
      android:label="@string/app_name"> 
    </activity> 
    <activity android:name=".Activity2"> 
      <intent-filter> 
          <action android:name="android.intent.action.MAIN" /> 
           <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 
 </application> 

 Activity2的代码如下:

public class Activity2 extends Activity {  
        private static final String TAG = "Activity2";  
        @Override 
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.main2);    
        }  
        @Override 
        public boolean onTouchEvent(MotionEvent event) {  
            Intent intent = new Intent(this, Activity1.class);  
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
            startActivity(intent);  
            return super.onTouchEvent(event);  
        }  
    } 

//activity1的启动模式改为new task ,并设置android:taskAffinity="com.example.task"

然后,我们再写一个应用MyActivity,它包含一个ActivityMyActivity),AndroidManifest.xml如下: 
<application

android:icon="@drawable/icon" android:label="@string/app_name"> 
    <activity android:name=".MyActivity" 
      
android:taskAffinity="com.example.task"
 
      android:label="@string/app_name"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN"/> 
     <category android:name="android.intent.category.LAUNCHER"/> 
     </intent-filter> 
   </activity> 
    我们首先启动MyActivity,然后按Home键,返回到桌面,然后打开Activity2,点击Activity2,进入Activity1(他的启动模式是new_task)。然后按返回键。 
           
我们发现,我们进入Activity的顺序为Activity2->Activity1,而返回时顺序为 Activity1->MyActivity。这就说明了一个问题,Activity1在启动时,重新宿主到了MyActivity所在的Task 中去了。

3.2 android:taskAffinity singleTask结合

 

    直接给结论:

    当一个应用程序加载一个singleTask模式的Activity时,首先该Activity会检查是否存在与它的taskAffinity相同的Task

    (1)、如果存在,那么检查是否实例化,如果已经实例化,那么销毁在该Activity以上的Activity并调用该ActivityonNewIntent()。如果没有实例化,那么该Activity实例化并入栈。

(2)、如果不存在,那么就重新创建Task,并入栈。

 

3.3 android:taskAffinity singleInstance结合

 

直接给出结论:

         (1)、当一个应用程序加载一个singleInstance模式的Activity时,如果该Activity没有被实例化,那么就重新创建一个Task,并入栈,如果已经被实例化,那么就调用该ActivityonNewIntent

(2)singleInstanceActivity所在的Task不允许存在其他Activity,任何从该Activity加载的其它 Actiivty(假设为Activity2)都会被放入其它的Task中,如果存在与Activity2相同affinityTask,则在该 Task内创建Activity2。如果不存在,则重新生成新的Task并入栈。

(3) 如果在奴隶应用application1当中定义两个activity,MainActivity和AActivity,将AActivity的启动模式设置为singleInstance,并设置其taskAffinity为com.example.master; 从MainActivity中启动AActivity,毫无疑问,此时会创建一个新的任务栈,名称是com.example.master,并将AActivity放置到栈中。然后将application1置于后台(按HOME键)。

打开宿主应用application2(默认的任务栈名称是com.example.master),此时惊奇地发现:此应用打开的是application1的AActivity,按后退键,退回到application2的MainActivity,由此可以看出,当声明为singleInstance的activity所在的任务栈被其他应用程序使用的时候,这个任务栈里面的原activity会丧失原来的singleInstance要求的一个activity在一个任务栈当中的属性,但是请注意:原来的这个activity始终是在栈顶的,后来加入的activity会都在这个activity的下面,但是还是按照栈的形式进出规则!

    (4)将上面的过程反过来,如果首先启动application2,系统当中存在了com.example.master 任务栈,然后启动SingleInstanceActivity,虽然他指定了taskAffinity,但是仍然不能将自己寄宿到com.example.master任务栈当中!他会重新开一个任务栈将自己放进去!

三、Activity的四种启动模式对Activity的启动有哪些影响?

重点说一下 singleTask,直接给结论:

1. 设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity,等于它的属性值taskAffinity的任务栈是否存在存在;如果存在这样的任务栈,它就会在这个任务栈中启动,否则就会在新任务栈中启动。因此,如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。

      2. 如果设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例,如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity实例会位于任务的堆栈顶端中(这个过程会调用该ActivityonNewIntent())

 

四、在Activity中使用startActivityForResult(intent, REQUESTCODE);onActivityResult()

是否与被启动的ActivitylaunchMode有关?如果有关,有什么关系?

1.通常情况下,当launchMode设置为standard或者singleTop的时候,程序的执行流程如下所示

2.如果launchMode设置为singleTask或者singleInstance的时候,程序就会在setResult之前调用

 onActivityResult(),这样就得不到从activity2返回的数据,所以需要注意!!!