我們首先從最簡單的開始,
standard
這個模式就是預設的模式,我們都知道 當你用這個模式時,每次傳送一個intent,都會生成一個新的例項!
我寫一個簡單的例子:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.administrator.lanuchmodetest"> 4 5 <application 6 android:allowBackup="true" 7 android:icon="@mipmap/ic_launcher" 8 android:label="@string/app_name" 9 android:supportsRtl="true" 10 android:theme="@style/AppTheme"> 11 <activity 12 android:name=".MainActivity" 13 android:label="@string/app_name" 14 android:theme="@style/AppTheme.NoActionBar"> 15 <intent-filter> 16 <action android:name="android.intent.action.MAIN" /> 17 18 <category android:name="android.intent.category.LAUNCHER" /> 19 </intent-filter> 20 </activity> 21 <activity 22 android:name=".TestMainActivity" 23 android:label="@string/title_activity_test_main" 24 android:theme="@style/AppTheme.NoActionBar"></activity> 25 </application> 26 27 </manifest>
對於這個app來說,MainActivity 是他的第一個預設啟動的acitivity,TestMainActivity是第二個activity,MainActivity上有一個按鈕 點選以後就傳送intent會跳轉到TestMainActivity上,
我重寫了TestMainActivity的onBackPressed方法,使得在這個activity上按返回鍵時 不會走系統自動銷燬的方法,而是傳送intent到MainActivity上來啟動MainActivity。
當我們重複了幾次這個動作以後,在命令列上輸入 adb shell dumpsys activity activities ,可以得到:
你看 這個就能清晰的看出來 當前我們這個app 有一個task棧,這個棧裡所有存在的activity都在這個task裡,有很多重複的。
當然了這個是最簡單的情況,我們現在考慮 如果是外部一個app 來啟動我們這個app裡的TestMainActivity是什麼情況?
現在我就來寫一個outerlanuchmodetest 的app 來啟動我們lanuchmodetest 這個app裡的 TestMainActivity 看看是什麼效果
(這裡程式碼太簡單略了),寫完以後執行 命令
你會發現 TestMain雖然是定義在lanuchmode這個app裡的但是 如果外部app啟動了他,他還是會在那個外部app裡的task!
於此同時,在我這個低於5.0(4.3版本)的模擬器裡,你開啟最近啟動app的列表 你會發現是這樣的:
同時我們點進去以後 會發現 我們必須點一次返回鍵才能回到我們的Outer這個app自己的介面。
singleTop
這個稍微有點難度,比上面稍微複雜點。實際上singletop和standrd 基本上差不多,也是可以有多個activity例項的,
唯一的不同在於:
如果呼叫的 目標activity 位於呼叫者的task的 棧頂,則不會建立新的例項,而是使用當前的這個activity 並呼叫onNewIntent方法。
目標 activity 位於呼叫者的task的棧頂,很多人理解不了,其實翻譯過來就是自己啟動自己。比如很多app裡的搜尋結果介面
就是這樣的,你每次搜尋 其實都是呼叫onNewIntent。設想一下,如果不用這個singleTop,那你搜尋100次 不就有100個搜尋頁面了
那你要回到上個頁面 得返回100次。
下面來做一個app,這個app的testMainActivity頁面 有個按鈕 點選他就啟動自己,我們看看會發生什麼?
我們可以看出來,當第一次啟動這個testmain的時候 onNewIntent是不走的 走的是onCreate ,以後每傳送一個
啟動這個頁面的intent,onCreate都不會走了 都是走的onNewIntent。
現在看看task裡的情況:
當然你要是從另外一個app去啟動的話 ,因為另外一個app 有自己的task 所以當然是可以有2個testMainActivity例項的:
singleTask
這個相對於singetop來說,這個又要複雜一些。
用這個啟動模式的,activity 在整個系統中都只有1個!注意是整個系統 而不是某個task 這是和top最大的區別。
如果這個例項存在 那就會由onNEWINTENT來 接受這個intent。這一點倒是和top一樣。
並且 會把他前面的 activity全部銷燬掉。
1 <activity 2 android:name=".TestMainActivity" 3 android:label="@string/title_activity_test_main" 4 android:launchMode="singleTask" 5 android:theme="@style/AppTheme.NoActionBar"> 6 <intent-filter> 7 <action android:name="android.intent.action.TEST_LANUCHMODE" /> 8 9 <category android:name="android.intent.category.DEFAULT" /> 10 </intent-filter> 11 </activity>
好,我們現在就來用圖的形式 來解釋一下這個過程:
我們假設main 點選以後跳轉到testmain
testmain 點選以後 跳轉到main2
main2 點選以後 跳轉到main3
此時的task 情況為:
此時main3 點選一下 跳轉到testmain以後的task情況為:
很符合我們的預期對吧,但是 如果你稍微改一下:
1 <activity 2 android:name=".TestMainActivity" 3 android:label="@string/title_activity_test_main" 4 android:launchMode="singleTask" 5 android:taskAffinity="" 6 android:theme="@style/AppTheme.NoActionBar"> 7 <intent-filter> 8 <action android:name="android.intent.action.TEST_LANUCHMODE" /> 9 10 <category android:name="android.intent.category.DEFAULT" /> 11 </intent-filter> 12 </activity>
你看 我們加了一個taskAffinity屬性,這個時候我們再重複一遍上述那個過程的第一步 你就會發現,此時的task情況是這樣的:
你看,這裡 我們發現 雖然都是一個應用內的activity互相啟動 但是當你加了這個屬性以後,我們由main 跳往testmain的時候
是新開的一個棧!而不是原來的main自己的那個棧了!當我們從main3 跳往testmain的時候:
依舊是如此! 所以要注意這個屬性 對singtask的影響!
包括你開啟工作管理員都是這樣的:
剛才我們講的是singtask的 應用內之間 的情況,現在來講一下 應用外跳轉的情況!
注意當跨應用跳轉時,taskAffinity 屬性就不影響singetask了。加不加都一樣(有興趣的同學可以自己試試)
當跨應用 跳轉時 情況如下:
1.當目標app程式不在的時候:
你看,此時我們還在活動的activity 就是系統的lanucher 和我們自己的outerlanuchmode。
此時如果啟動lanuchmode 這個app裡的testmain,那麼就會:
你看 此時系統task 就是這樣的,
所以針對這種情況 結論就是:當目標activity所屬的app沒有啟動,並且activity屬性屬於singetask的時候,
呼叫者 啟動這個acitivity的結果就是 必定會在另外一個task裡!
2.第二種情況:
目標activity所屬的app 已經啟動了,但是目標activity還沒有啟動
此時如果點選啟動目標activity
結果也很明瞭,當然還有另外一種複雜的情況,如果目標activity已經有了testmainactivity 存在 會怎麼樣,這裡就不寫了,
有興趣的同學可以自己寫個demo 看下task的情況。
singleInstance
最後看一下 這個單例模式,其實這個最簡單,就是無論什麼時候,這個屬性的activity 都是自己單獨佔據一個棧的。
並且和前面的singleTask類似,在系統中 只有一份!
比方說我們從main 跳轉到testmain 這個單例:
1 <activity 2 android:name=".TestMainActivity" 3 android:label="@string/title_activity_test_main" 4 android:launchMode="singleInstance" 5 android:theme="@style/AppTheme.NoActionBar"> 6 <intent-filter> 7 <action android:name="android.intent.action.TEST_LANUCHMODE" /> 8 9 <category android:name="android.intent.category.DEFAULT" /> 10 </intent-filter> 11 </activity>
看上去 是和singletask 一樣,但是如果你開啟工作管理員 你會發現:
只有一個!
並且當你從工作管理員 進入到這個介面時,你點返回 是無法回到main的!
所以說這種情況 雖然是2個task ,但是系統在工作管理員只顯示一個!
並且返回回不到前面一個acitivity,這樣的體驗非常糟糕 一定要慎用!
當然解決方法也有,只要加上taskaffinity屬性即可!
加上以後 你再開啟工作管理員 就是:
一切正常。
不過還是想多說一句 單例模式 儘量慎用,尤其是不帶taskaffinity屬性的,據我目前看過的原始碼裡面 應該只有
某些手機rom裡的lanucher 會用這個屬性,其他任何app中 我都沒有見過用這個屬性的。所以大家也一定要慎用!
因為會給使用者造成困惑!