android 当中taskAffinity属性与launchMode相关
一、本文嘗試解釋以下問題
1.? Activity被啟動之后放在哪個任務棧當中?與哪些因素有關?
2.? Activity的四種啟動模式對Activity的啟動有哪些影響?
3.? 在Activity中使用startActivityForResult(intent, REQUESTCODE);和onActivityResult()
??? 是否與被啟動的Activity的launchMode有關?如果有關,有什么關系?
二、Activity被啟動之后放在哪個任務棧當中?與哪些因素有關?
1.基本論斷:Activity啟動之后對應的任務站與Activity的兩個屬性taskAffinity和allowTask-
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-sdkandroid:minSdkVersion="8"android:targetSdkVersion="17" /><applicationandroid:allowBackup="true"android:theme="@style/AppTheme" ><activityandroid: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"……><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme"><activityandroid: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如下(根activity加android: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"……><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid: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><activityandroid: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)基本論斷
如果加載某個Activity的intent,Flag被設置成FLAG_ACTIVITY_NEW_TASK時,它會首先檢查是否存在與自己taskAffinity相同的Task,如果存在,那么它會直接宿主到該Task中,如果不存在則重新創建Task。?
(2)測試。?
??? ??我們首先寫一個應用,它有兩個Activity(Activity1和Activity2),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,它包含一個Activity(MyActivity),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并調用該Activity的onNewIntent()。如果沒有實例化,那么該Activity實例化并入棧。
(2)、如果不存在,那么就重新創建Task,并入棧。
?
3.3?android:taskAffinity?與singleInstance結合
?
直接給出結論:
???????? (1)、當一個應用程序加載一個singleInstance模式的Activity時,如果該Activity沒有被實例化,那么就重新創建一個Task,并入棧,如果已經被實例化,那么就調用該Activity的onNewIntent;
(2)、singleInstance的Activity所在的Task不允許存在其他Activity,任何從該Activity加載的其它?Actiivty(假設為Activity2)都會被放入其它的Task中,如果存在與Activity2相同affinity的Task,則在該?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實例會位于任務的堆棧頂端中(這個過程會調用該Activity的onNewIntent())。
?
四、在Activity中使用startActivityForResult(intent, REQUESTCODE);和onActivityResult()
是否與被啟動的Activity的launchMode有關?如果有關,有什么關系?
1.通常情況下,當launchMode設置為standard或者singleTop的時候,程序的執行流程如下所示
2.如果launchMode設置為singleTask或者singleInstance的時候,程序就會在setResult之前調用
?onActivityResult(),這樣就得不到從activity2返回的數據,所以需要注意!!!
轉自:http://my.oschina.net/u/1865711/blog/289663
總結
以上是生活随笔為你收集整理的android 当中taskAffinity属性与launchMode相关的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Adb connection Error
- 下一篇: Android Installation