標籤:
參考:http://blog.csdn.net/zhangjg_blog/article/details/10923643#
singleInstance的特點可以歸結為以下三條:
- 以singleInstance模式啟動的Activity具有全域唯一性,即整個系統中只會存在一個這樣的執行個體
- 以singleInstance模式啟動的Activity具有獨佔性,即它會獨自佔用一個任務,被他開啟的任何activity都會運行在其他任務中(官方文檔上的描述為,singleInstance模式的Activity不允許其他Activity和它共存在一個任務中)
- 被singleInstance模式的Activity開啟的其他activity,能夠開啟一個新任務,但不一定開啟新的任務,也可能在已有的一個任務中開啟
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jg.zhang.androidtasktest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="androidtasktest"> <activity android:name="com.jg.zhang.androidtasktest.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.jg.zhang.androidtasktest.SecondActivity" android:launchMode="singleInstance"> <intent-filter> <action android:name="com.jg.zhang.androidtasktest.ACTION_MY"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity> <activity android:name="com.jg.zhang.androidtasktest.ThirdActivity"/> </application> </manifest>
由上面的資訊清單檔可以知道,該應用程式套件括三個activity,分別為MianActivity,SecondActivity,ThirdActivity,其中SecondActivity啟動模式設定為singleInstance。MianActivity可以開啟SecondActivity,SecondActivity可以開啟ThirdActivity。 並且為了可以在其他應用中開啟SecondActivity,為SecondActivity設定了一個IntentFilter,這樣就可以在其他應用中使用隱式Intent開啟SecondActivity。
為了更好的驗證singleInstance的全域唯一性,還需要其他一個應用,對上面的AndroidTaskTest1進行一些修改即可。AndroidTaskTest1隻需要一個MianActivity,在MainActivity中點擊按鈕會開啟AndroidTaskTest應用中的SecondActivity。開啟AndroidTaskTest應用中的SecondActivity的代碼如下
/** * 該方法在布局中按鈕的android:onClick屬性中指定 * android:onClick="launchOtherActivity" * @param v */public void launchOtherActivity(View v){Intent intent = new Intent();//以下Action為"com.jg.zhang.androidtasktest.ACTION_MY"//即AndroidTaskTest應用中SecondActivity的actionintent.setAction("com.jg.zhang.androidtasktest.ACTION_MY");startActivity(intent);}
執行如下操作:安裝AndroidTaskTest應用,點擊MainActivity中的按鈕,開啟SecondActivity,可以看到如下log輸出:
執行adb shell dumpsys activity命令,有以下輸出:
TaskRecord{411189e0 #9 A com.jg.zhang.androidtasktest}
Run #2: ActivityRecord{4129af80 com.jg.zhang.androidtasktest/.SecondActivity}
TaskRecord{41305528 #8 A com.jg.zhang.androidtasktest}
Run #1: ActivityRecord{41296e60 com.jg.zhang.androidtasktest/.MainActivity}
以上可以說明,singleInstance模式的Activity總是會在新的任務中運行(前提是系統中還不存在這樣的一個執行個體) 。
下面驗證它的全域唯一性,執行以下操作:安裝另一個應用AndroidTaskTest1,在開啟的MainActivity中點擊按鈕開啟AndroidTaskTest應用中的SecondActivity。看到列印出一條新的日誌:
執行adb shell dumpsys activity命令,有以下輸出:
TaskRecord{411189e0 #9 A com.jg.zhang.androidtasktest}
Run #3: ActivityRecord{4129af80 com.jg.zhang.androidtasktest/.SecondActivity}
TaskRecord{412dc788 #12 A com.jg.zhang.androidtasktest1}
Run #2: ActivityRecord{4121c628 com.jg.zhang.androidtasktest1/.MainActivity}
TaskRecord{41305528 #8 A com.jg.zhang.androidtasktest}
Run #1: ActivityRecord{41296e60 com.jg.zhang.androidtasktest/.MainActivity}
由紅色字型可以得知,開啟的SecondActivity就是上次建立的編號為4129af80的SecondActivity,並且Log中沒有再次輸出關於SecondActivity的資訊,說明SecondActivity並沒有重新建立。由此可以得出結論:以singleInstance模式啟動的Activity在整個系統中是單例的,如果在啟動這樣的Activity時,已經存在了一個執行個體,那麼會把它所在的任務調度到前台,重用這個執行個體。
下面開始驗證第二個特點:以singleInstance模式啟動的Activity具有獨佔性,即它會獨自佔用一個任務,被他開啟的任何activity都會運行在其他任務中 重新安裝AndroidTaskTest應用,點擊MainActivity中的按鈕,開啟SecondActivity,在SecondActivity中點擊按鈕,開啟ThirdActivity。可以看到有如下Log輸出: 。。。 SecondActivity所在的任務為16,被SecondActivity啟動的ThirdActivity所在的任務為15,這就說明
以singleInstance模式啟動的Activity具有獨佔性,即它會獨自佔用一個任務,被他開啟的任何activity都會運行在其他任務中 下面開始驗證第三個特點:被singleInstance模式的Activity開啟的其他activity,能夠在新的任務中啟動,但不一定開啟新的任務,也可能在已有的一個任務中開啟 有上面對第二個特點的驗證可以看到,被SecondActivity啟動的ThirdActivity並沒有運行在一個新開啟的任務中,而是和MainActivity運行在了同一個已有的任務中,那麼在什麼情況下ThirdActivity才會啟動一個新的任務呢? 現在對程式的資訊清單檔做以下修改,為ThirdActivity增加一個屬性taskAffinity:
<activity android:name="com.jg.zhang.androidtasktest.ThirdActivity" android:taskAffinity="com.jg.zhang.androidtasktest.second"/>
重新安裝AndroidTaskTest應用,執行和上一步中同樣的操作:點擊MainActivity中的按鈕,開啟SecondActivity,在SecondActivity中點擊按鈕,開啟ThirdActivity。可以看到有如下輸出:
執行adb shell dumpsys activity命令,有以下輸出:
TaskRecord{413551b0 #20 A com.jg.zhang.androidtasktest.second}
Run #3: ActivityRecord{412de9c0 com.jg.zhang.androidtasktest/.ThirdActivity}
TaskRecord{4134b268 #19 A com.jg.zhang.androidtasktest}
Run #2: ActivityRecord{412a36a0 com.jg.zhang.androidtasktest/.SecondActivity}
TaskRecord{413131e8 #18 A com.jg.zhang.androidtasktest}
Run #1: ActivityRecord{41271e10 com.jg.zhang.androidtasktest/.MainActivity}
可見,被SecondActivity啟動的ThirdActivity啟動在了一個新的任務中,即在啟動ThirdActivity時建立了一個新任務。這就說明被singleInstance模式的Activity A在開啟另一activity B時,能夠開啟一個新任務,但是是不是真的開啟新任務,還要受其他條件的限制,這個條件是:當前系統中是不是已經有了一個activity B的taskAffinity屬性指定的任務。 其實這種行為和singleTask啟動時的情況相同。在Activity的啟動模式設定為singleTask時,啟動時系統會為它加上FLAG_ACTIVITY_NEW_TASK標誌,而被singleInstance模式的Activity開啟的activity,啟動時系統也會為它加上FLAG_ACTIVITY_NEW_TASK標誌,所以他們啟動時的情況是相同的,上面再驗證singleTask時已經闡述過,現在重新說明一下:
由於ThirdActivity是被啟動模式為singleInstance類型的Activity(即SecondActivity)啟動的,framework會為它它加上FLAG_ACTIVITY_NEW_TASK標誌,這時 framework會檢索是否已經存在了一個affinity為com.jg.zhang.androidtasktest.second(即ThirdActivity的taskAffinity屬性)的任務,
- 如果存在這樣的一個任務,則檢查在這個任務中是否已經有了一個ThirdActivity的執行個體,
- 如果已經存在一個ThirdActivity的執行個體,則會重用這個任務和任務中的ThirdActivity執行個體,將這個任務調到前台,清除位於ThirdActivity上面的所有Activity,顯示ThirdActivity,並調用ThirdActivity的onNewIntent()。
- 如果不存在一個ThirdActivity的執行個體,會在這個任務中建立ThirdActivity的執行個體,並調用onCreate()方法
- 如果不存在這樣的一個任務,會建立一個新的affinity為com.jg.zhang.androidtasktest.second的任務,並且將ThirdActivity啟動到這個新的任務中
如果ThirdActivity不設定taskAffinity,即ThirdActivity和MainActivity的taskAffinity相同,都為應用的包名,那麼ThirdActivity是不會開啟一個新任務的,framework中的判定過程如下:
- 在SecondActivity啟動ThirdActivity時,因為SecondActivity是singleInstance的,所以設定ThirdActivity的啟動標誌為FLAG_ACTIVITY_NEW_TASK
- 然後獲得ThirdActivity的taskAffinity,即為包名com.jg.zhang.androidtasktest
- 檢查是否已經存在一個affinity為com.jg.zhang.androidtasktest的任務,這個任務是存在的,就是MainActivity所在的任務,這個任務是在啟動MainActivity時開啟的
- 既然已經存在這個任務,就檢索在這個任務中是否存在一個ThirdActivity的執行個體,發現不存在
- 在這個已有的任務中啟動一個SecondActivity的執行個體
為了作一個清楚的比較,列出ThirdActivity的taskAffinity屬性設為com.jg.zhang.androidtasktest.second時的啟動過程
- 在SecondActivity啟動ThirdActivity時,因為SecondActivity是singleInstance的,那麼設定ThirdActivity的啟動標誌為FLAG_ACTIVITY_NEW_TASK
- 然後獲得ThirdActivity的taskAffinity,即為com.jg.zhang.androidtasktest.second
- 檢查是否已經存在一個affinity為com.jg.zhang.androidtasktest.second的任務,這個任務是不存在的
- 建立一個新的affinity為com.jg.zhang.androidtasktest.second的任務,並且將ThirdActivity啟動到這個新的任務
到此singleInstance也介紹完了。
android Activity launch mode 一個執行個體 singleInstance