LaunchMode
在聲明Activity的xml中指定 android:launchMode="xxx"
standard
標(biāo)準(zhǔn)模式。這是系統(tǒng)默認(rèn)的模式,每次啟動Activity都會重新創(chuàng)建一個新的Activity實(shí)例,也就是onCreate,onStart,onResume流程走一遍,并且一個任務(wù)棧里允許存在多個實(shí)例。
當(dāng)我們使用ApplicationContext去啟動Activity的時候,因?yàn)槟J(rèn)是standard模式會報(bào)錯:
Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
因?yàn)閟tandard 模式默認(rèn)啟動的Activity會和啟動它的Activity在同一任務(wù)棧,而由于ApplicationContext非Activity的Context,并沒有所謂的任務(wù)棧,所以提示我們需要使用FLAG_ACTIVITY_NEW_TASK來新建一個任務(wù)棧并把啟動的Activity放進(jìn)去。
singleTop
棧頂復(fù)用模式。在同一個任務(wù)棧中棧頂如果有此Activity的實(shí)例,那么不會重新創(chuàng)建一個新實(shí)例,而是調(diào)用此Activity的onNewIntent,此時onCreate、onStart不會被調(diào)用。但如果此Activity在同一個任務(wù)棧但不在棧頂或之前用standard模式啟動的,就會重新創(chuàng)建。
如ADBCD(第一個D不在棧頂則重新創(chuàng)建),ABCDD(第一個D為standard模式啟動也會重新創(chuàng)建)。
singleTask
棧內(nèi)復(fù)用模式。在同一個任務(wù)棧(注意:不一定是棧頂了)中如果有此Activity的實(shí)例,那么不會重新創(chuàng)建一個新實(shí)例,而是調(diào)用此Activity的onNewIntent,此時onCreate、onStart不會被調(diào)用。并且自帶FLAG_ACTIVITY_CLEAR_TOP效果。
同一個棧內(nèi)。如ADBC(要啟動D,則把D挪到棧頂,BC由于clearTop而被移除棧,剩下AD)。
如果D指定棧為S2,android:taskAffinity="S2",而啟動它的Activity棧為S1,則先創(chuàng)建S2棧然后再new D放到S2中。
singleInstance
單例模式。這是一種加強(qiáng)的singleTask模式。除了singleTask模式所有特性外,它只能單獨(dú)在一個任務(wù)棧中,跟其他Activity不能同時存在一個任務(wù)棧,整個Application也只有一個實(shí)例。
Intent的Flag
我們在代碼里面通過Intent啟動Activity的時候可以添加flag,如 :
intent.addFlags(Intent.FLAG_ACTIVITY_XXX);
FLAG_ACTIVITY_BROUGHT_TO_FRONT
這個標(biāo)志一般不是由程序代碼設(shè)置的,如在launchMode中設(shè)置singleTask模式時系統(tǒng)幫你設(shè)定。
FLAG_ACTIVITY_CLEAR_TASK
此Activity將變成一個新Task中新的最底端的Activity,所有的之前此Activity實(shí)例和包含該實(shí)例的Task都會被關(guān)閉,這個標(biāo)識僅僅和FLAG_ACTIVITY_NEW_TASK聯(lián)合起來才能使用。
FLAG_ACTIVITY_NEW_TASK
與launchMode="singleTask"一樣的效果。
FLAG_ACTIVITY_CLEAR_TOP
清除包含此Activity的Task中位于該Activity實(shí)例之上的其他Activity實(shí)例。這種行為的 launchMode 屬性沒有對應(yīng)的值,只能通過代碼設(shè)置。
單獨(dú)使用的情況:ABCD 啟動 B ,會銷毀B和B以上的實(shí)例 變成 AB ,B 重新執(zhí)行onCreate -> onStart
配合FLAG_ACTIVITY_SINGLE_TOP使用,則 B 不會銷毀只銷毀B以上實(shí)例,然后B 執(zhí)行onNewIntent -> onStart
配合FLAG_ACTIVITY_NEW_TASK則是singleTask效果
FLAG_ACTIVITY_SINGLE_TOP
與launchMode="singleTop"一樣的效果。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
設(shè)置了的話該Activity則不出現(xiàn)在最近使用的列表中。
FLAG_ACTIVITY_FORWARD_RESULT
如果A需要onActivityResult中獲取返回結(jié)果,startActivityForResult B,而B只是過渡頁,啟動C之后就finish掉了,需要在 C 中setResult返回給A就可以用到這個標(biāo)志。
A -> B -> XXXXX(無論多少個過渡頁) 設(shè)置 FLAG_ACTIVITY_FORWARD_RESULT 來啟動 C ,之后該XXX過渡頁finish - > C ,那么C的結(jié)果返回給A
FLAG_ACTIVITY_NO_HISTORY
如果設(shè)置,新的Activity將不再歷史stack中保留。用戶一離開它,這個Activity就關(guān)閉了。
例如A啟動B的時候,給B設(shè)置了FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY,那么:
A -> B -> C ,啟動C 就算 B沒有自行finish ,也會變?yōu)?AC
FLAG_ACTIVITY_NO_ANIMATION
啟動的時候不執(zhí)行動畫。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
當(dāng)用戶點(diǎn)擊Home,從歷史中選擇該Activity,系統(tǒng)會自動加上這個Flag。
FLAG_ACTIVITY_NO_USER_ACTION
在onPause()之前會調(diào)用onUserLeaving( )方法,如果使用了該標(biāo)識,說明目標(biāo)Activity不和用戶交互,所以也就不需要回調(diào)onUserLeaving( )方法。
FLAG_ACTIVITY_REORDER_TO_FRONT
如果設(shè)置這個標(biāo)記,新啟動的Activity將會被放到它所屬task的最前面
例如,假如有一個Task包含4個Activity:A,B,C,D.如果D通過調(diào)用startActivity( )來啟動B,如果使用了這個標(biāo)記,B將會排在這個task的最上面,也即現(xiàn)在的順序變成了A,C,D,B。
如果使用了FLAG_ACTIVITY_CLEAR_TOP,這個標(biāo)記將會被忽略。
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
如果設(shè)置該屬性,并且這個Activity在一個新的Task中正在被啟動或者被帶到一個已經(jīng)存在的Task的頂部,這時這個Task會被重置(即該Task中之前的Activity會被關(guān)閉),該Activity成為棧底第一個Activity。
FLAG_ACTIVITY_TASK_ON_HOME
把當(dāng)前新啟動的任務(wù)置于Home任務(wù)之上,也就是按back鍵從這個任務(wù)返回的時候會回到Home,即使這個不是他們最后看見的Activity。
注意這個標(biāo)記必須和FLAG_ACTIVITY_NEW_TASK加上android:taskAffinity一起使用。
FLAG_DEBUG_LOG_RESOLUTION
用來調(diào)試,當(dāng)設(shè)置這個標(biāo)志的時候,在解析這個intent的時候,將會打出打印信息(queryIntent函數(shù))。
FLAG_INCLUDE_STOPPED_PACKAGES 和 FLAG_DEBUG_LOG_RESOLUTION
從Android 3.1開始,給Intent定義了兩個新的Flag,分別為FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES,用來控制Intent是否要對處于停止?fàn)顟B(tài)的App起作用,顧名思義:
FLAG_INCLUDE_STOPPED_PACKAGES:表示包含未啟動的App
FLAG_EXCLUDE_STOPPED_PACKAGES:表示不包含未啟動的App
值得注意的是,Android 3.1開始,系統(tǒng)向所有Intent的廣播添加了FLAG_EXCLUDE_STOPPED_PACKAGES標(biāo)志。這樣做是為了防止廣播無意或不必要地開啟未啟動App的后臺服務(wù)。如果要強(qiáng)制調(diào)起未啟動的App,后臺服務(wù)或應(yīng)用程序可以通過向廣播Intent添加FLAG_INCLUDE_STOPPED_PACKAGES標(biāo)志來喚醒。
FLAG_FROM_BACKGROUND
Intent不光可以在Acitivity里面start,還可以從service里面啟動,這個參數(shù)就表示這個Intent是從后臺服務(wù)發(fā)起的。
FLAG_GRANT_PERSISTABLE_URI_PERMISSION
區(qū)別于 FLAG_GRANT_READ_URI_PERMISSION 跟 FLAG_GRANT_WRITE_URI_PERMISSION, URI權(quán)限會持久存在即使重啟,直到明確的用 revokeUriPermission(Uri, int) 撤銷。 這個flag只提供可能持久授權(quán)。但是接收的應(yīng)用必須調(diào)用ContentResolver的takePersistableUriPermission(Uri, int)方法實(shí)現(xiàn) 。
FLAG_GRANT_PERSISTABLE_URI_PERMISSION
Uri 權(quán)限授予任何原始授權(quán)URI前綴匹配的URI。
FLAG_GRANT_PERSISTABLE_URI_PERMISSION
結(jié)合FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION 使用。
Uri 權(quán)限授予任何原始授權(quán)URI前綴匹配的URI。如果沒有這個標(biāo)志則必須精確匹配Uri了。
FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION
臨時訪問讀權(quán)限和寫權(quán)限 。Intent的接受者將被授予 INTENT 數(shù)據(jù) uri 或者 在ClipData 上的讀/寫權(quán)限。
FLAG_RECEIVER_FOREGROUND
當(dāng)發(fā)送廣播時,允許其接受者 在前臺運(yùn)行的擁有更高的優(yōu)先級,更短的超時間隔。
FLAG_RECEIVER_NO_ABORT
如果是有序廣播,不要允許接收者中斷廣播播。
FLAG_RECEIVER_REGISTERED_ONLY
設(shè)置之后就不能通過xml來注冊監(jiān)聽這個廣播了,必須動態(tài)注冊。
很多毒病程序?yàn)榱俗C保自己被止終后可以再次行運(yùn),都會在xml中冊注一些系統(tǒng)廣播,妄圖利用這些系統(tǒng)高頻廣播來實(shí)現(xiàn)自動啟。
比如在老版本的android系統(tǒng)中,毒病程序可以通過監(jiān)聽TIME_TICK來動啟自己的service后臺行運(yùn),做一些秘隱的作工,而且就算自己被kill失落了,也能很快重新動啟。
而一旦這些系統(tǒng)廣播加了flag FLAG_RECEIVER_REGISTERED_ONLY,這些毒病程序就沒轍了。
例如系統(tǒng)的TIME_TICK廣播,由AlarmManagerService發(fā)送,我們看源碼可以看到
mTimeTickSender = PendingIntent.getBroadcast(context, 0,
new Intent(Intent.ACTION_TIME_TICK).addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0);
這樣就不能監(jiān)聽ACTION_TIME_TICK來自啟動了。
FLAG_RECEIVER_REPLACE_PENDING
這個Flag 將會將之前的Intent 替代掉。加了這個Flag,在發(fā)送一系列的這樣的Intent 之后,中間有些Intent 有可能在你還沒有來得及處理的時候,就被替代掉了。
FLAG_ACTIVITY_NEW_DOCUMENT(原FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
可以跟FLAG_ACTIVITY_MULTIPLE_TASK結(jié)合使用,當(dāng)只用自己的時候相當(dāng)于Manifast中 android.R.attr.documentLaunchMode="intoExisting",當(dāng)跟FLAG_ACTIVITY_MULTIPLE_TASK 結(jié)合使用相當(dāng)于 Manifast中android.R.attr.documentLaunchMode="always"。
FLAG_ACTIVITY_RETAIN_IN_RECENTS
默認(rèn)情況下通過FLAG_ACTIVITY_NEW_DOCUMENT啟動的Activity在關(guān)閉之后,Task中的記錄會相對應(yīng)的刪除。如果為了能夠重新啟動這個Activity你想保留它,就可以使用者個flag,最近的記錄將會保留在接口中以便用戶去重新啟動。接受該Flag的Activity可以使用autoRemoveFromRecents去復(fù)寫這個request或者調(diào)用Activity.finishAndRemoveTask( )方法。
FLAG_ACTIVITY_MULTIPLE_TASK
這個標(biāo)識用來創(chuàng)建一個新的task棧,并且在里面啟動新的activity(所有情況,不管系統(tǒng)中存在不存在該activity實(shí)例),經(jīng)常和FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK一起使用。這上面兩種使用場景下,如果沒有帶上FLAG_ACTIVITY_MULTIPLE_TASK標(biāo)識,他們都會使系統(tǒng)搜索存在的task棧,去尋找匹配intent的一個activity,如果沒有找到就會去新建一個task棧;但是當(dāng)和FLAG_ACTIVITY_MULTIPLE_TASK一起使用的時候,這兩種場景都會跳過搜索這步操作無條件的創(chuàng)建一個新的task。和FLAG_ACTIVITY_NEW_TASK一起使用需要注意,盡量不要使用該組合除非你完成了自己的頂部應(yīng)用啟動器,他們的組合使用會禁用已經(jīng)存在的task?;氐角芭_的功能。
taskAffinity 和 allowTaskReparenting
taskAffinity用于指定當(dāng)前Activity所關(guān)聯(lián)的Task,allowTaskReparenting用于配置是否允許該Activity可以更換從屬Task,通常情況二者連在一起使用,用于實(shí)現(xiàn)把一個應(yīng)用程序的Activity移到另一個應(yīng)用程序的Task中。
allowTaskReparenting用來標(biāo)記Activity能否從啟動的Task移動到taskAffinity指定的Task,默認(rèn)是繼承至application中的allowTaskReparenting=false,如果為true,則表示可以更換;false表示不可以。
例如在A應(yīng)用中啟動了B應(yīng)用的Activity,如果設(shè)置allowTaskReparenting=true,則Activity允許從A的Task移動到B的Task。但如果A被啟動之后,Activity就會回到A的Task中。