1、本文嘗試解釋如下問題android
1. Activity被啓動以後放在哪一個任務棧當中?與哪些因素有關?app
2. Activity的四種啓動模式對Activity的啓動有哪些影響?ide
3. 在Activity中使用startActivityForResult(intent, REQUESTCODE);和onActivityResult()
測試
是否與被啓動的Activity的launchMode有關?若是有關,有什麼關係?this
2、Activity被啓動以後放在哪一個任務棧當中?與哪些因素有關?spa
1.基本論斷:Activity啓動以後對應的任務站與Activity的兩個屬性taskAffinity和allowTask-xml
Reparenting有關生命週期
2.原理utf-8
(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以下(根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"
……>
<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)基本論斷
若是加載某個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任務棧當中!他會從新開一個任務棧將本身放進去!
3、Activity的四種啓動模式對Activity的啓動有哪些影響?
重點說一下 singleTask,直接給結論:
1. 設置了"singleTask"啓動模式的Activity,它在啓動的時候,會先在系統中查找屬性值affinity,等於它的屬性值taskAffinity的任務棧是否存在存在;若是存在這樣的任務棧,它就會在這個任務棧中啓動,不然就會在新任務棧中啓動。所以,若是咱們想要設置了"singleTask"啓動模式的Activity在新的任務中啓動,就要爲它設置一個獨立的taskAffinity屬性值。
2. 若是設置了"singleTask"啓動模式的Activity不是在新的任務中啓動時,它會在已有的任務中查看是否已經存在相應的Activity實例,若是存在,就會把位於這個Activity實例上面的Activity所有結束掉,即最終這個Activity實例會位於任務的堆棧頂端中(這個過程會調用該Activity的onNewIntent())。
4、在Activity中使用startActivityForResult(intent, REQUESTCODE);和onActivityResult()
是否與被啓動的Activity的launchMode有關?若是有關,有什麼關係?
1.一般狀況下,當launchMode設置爲standard或者singleTop的時候,程序的執行流程以下所示
2.若是launchMode設置爲singleTask或者singleInstance的時候,程序就會在setResult以前調用
onActivityResult(),這樣就得不到從activity2返回的數據,因此須要注意!!!