在一個項目中會包括着多個Activity,系統中使用任務棧來存儲建立的Activity實例,任務棧是一種「後進先出」的棧結構。舉個栗子,若咱們屢次啓動同一個Activity。系統會建立多個實例依次放入任務棧中。當按back鍵返回時,每按一次,一個Activity出棧,直到棧空爲止。當棧中無不論什麼Activity。系統就會回收此任務棧。android
上面這個樣例中的Activity並無設置啓動模式,你會發現屢次啓動同一個Activity。而系統卻建立了多個實例,白白浪費內存,這樣的狀況Android早就替咱們考慮好了。Android爲Activity 的建立提供了4種啓動模式,而依據實際應用場景的不一樣。爲Activity 選擇不一樣的啓動模式,最大化下降了每次都需要在棧中建立一個新的Activity的壓力,下降內存使用。ide
啓動模式的具體說明和使用場景?如下依據這篇博文來一一解惑。.net
一. Android啓動模式具體解釋設計
1. Standard 標準模式
說明: Android建立Activity時的默認模式,假設沒有爲Activity設置啓動模式的話,默以爲標準模式。每次啓動一個Activity都會又一次建立一個新的實例入棧,不管這個實例是否存在。xml
生命週期:如上所看到的,每次被建立的實例Activity 的生命週期符合典型狀況,它的onCreate、onStart、onResume都會被調用。blog
舉例:此時Activity 棧中以此有A、B、C三個Activity,此時C處於棧頂,啓動模式爲Standard 模式。生命週期
若在C Activity中加入點擊事件,需要跳轉到還有一個同類型的C Activity。結果是還有一個C Activity進入棧中,成爲棧頂。 事件
2. SingleTop 棧頂複用模式
說明:分兩種處理狀況:需要建立的Activity已經處於棧頂時,此時會直接複用棧頂的Activity。不會再建立新的Activity;若需要建立的Activity不處於棧頂,此時會又一次建立一個新的Activity入棧,同Standard模式同樣。ip
生命週期:若狀況一中棧頂的Activity被直接複用時,它的onCreate、onStart不會被系統調用,因爲它並無發生改變。但是一個新的方法 onNewIntent會被回調(Activity被正常建立時不會回調此方法)。內存
舉例:此時Activity 棧中以此有A、B、C三個Activity,此時C處於棧頂,啓動模式爲SingleTop 模式。狀況一:在C Activity中加入點擊事件,需要跳轉到還有一個同類型的C Activity。
結果是直接複用棧頂的C Activity。
狀況二:在C Activity中加入點擊事件,需要跳轉到還有一個A Activity。結果是建立一個新的Activity入棧。成爲棧頂。
3. SingleTask 棧內複用模式
說明:若需要建立的Activity已經處於棧中時,此時不會建立新的Activity,而是將存在棧中的Activity上面的其餘Activity全部銷燬,使它成爲棧頂。
生命週期:同SingleTop 模式中的狀況一一樣。僅僅會又一次回調Activity中的 onNewIntent方法
舉例:此時Activity 棧中以此有A、B、C三個Activity。此時C處於棧頂,啓動模式爲SingleTask 模式。
狀況一:在C Activity中加入點擊事件,需要跳轉到還有一個同類型的C Activity。結果是直接用棧頂的C Activity。狀況二:在C Activity中加入點擊事件,需要跳轉到還有一個A Activity。
結果是將A Activity上面的B、C全部銷燬,使A Activity成爲棧頂。
4. SingleInstance 單實例模式
說明: SingleInstance比較特殊,是全局單例模式,是一種增強的SingleTask模式。它除了具備它全部特性外,還增強了一點:具備此模式的Activity僅僅能單獨位於一個任務棧中。
這個常用於系統中的應用,好比Launch、鎖屏鍵的應用等等,整個系統中僅僅有一個!因此在咱們的應用中通常不會用到。瞭解就能夠。
舉例:比方 A Activity是該模式,啓動A後。系統會爲它建立一個單獨的任務棧,因爲棧內複用的特性。興許的請求均不會建立新的Activity,除非這個獨特的任務棧被系統銷燬。
二.啓動模式的使用方式
1. 在 Manifest.xml中指定Activity啓動模式
一種靜態的指定方法,在Manifest.xml文件裏聲明Activity的同一時候指定它的啓動模式,這樣在代碼中跳轉時會依照指定的模式來建立Activity。樣例例如如下:
<activity android:name="..activity.MultiportActivity" android:launchMode="singleTask"/>
2. 啓動Activity時。在Intent中指定啓動模式去建立Activity
一種動態的啓動模式,在new 一個Intent後,經過Intent的addFlags方法去動態指定一個啓動模式。樣例例如如下:
Intent intent = new Intent();
intent.setClass(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
注意:以上兩種方式都可以爲Activity指定啓動模式,但是兩者仍是有差異的。
(1)優先級:動態指定方式即另一種比第一種優先級要高,若二者同一時候存在,以另一種方式爲準。
(2)限定範圍:第一種方式沒法爲Activity直接指定 FLAG_ACTIVITY_CLEAR_TOP 標識,另一種方式沒法爲Activity指定 singleInstance 模式。
三. Activity 的 Flags
標記位既可以設定Activity的啓動模式,如同上面介紹的,在動態指定啓動模式,比方 FLAG_ACTIVITY_NEW_TASK 和 FLAG_ACTIVITY_SINGLE_TOP 等。它還可以影響Activity 的運行狀態 ,比方 FLAG_ACTIVITY_CLEAN_TOP 和 FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 等。
如下介紹幾個基本的標記位,切勿死記,理解幾個就能夠,需要時再查官方文檔。
1. FLAG_ACTIVITY_NEW_TASK
做用是爲Activity指定 「SingleTask」啓動模式。跟在AndroidMainfest.xml指定效果一樣。
2. FLAG_ACTIVITY_SINGLE_TOP
做用是爲Activity指定 「SingleTop」啓動模式,跟在AndroidMainfest.xml指定效果一樣。
3. FLAG_ACTIVITY_CLEAN_TOP
具備此標記位的Activity,啓動時會將與該Activity在同一任務棧的其餘Activity出棧。通常與SingleTask啓動模式一塊兒出現。它會完畢SingleTask的做用。但事實上SingleTask啓動模式默認具備此標記位的做用
4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具備此標記位的Activity不會出現在歷史Activity的列表中,使用場景:當某些狀況下咱們不但願用戶經過歷史列表回到Activity時,此標記位便體現了它的效果。它等同於在xml中指定Activity的屬性:
android:excludeFromRecents="trure"
四. 啓動模式的實際應用場景
這四種模式中的Standard模式是最普通的一種,沒有什麼特別注意。而SingleInstance模式是整個系統的單例模式,在咱們的應用中通常不會應用到。因此,這裏就具體解說 SingleTop 和 SingleTask模式的運用場景:
1. SingleTask模式的運用場景
最多見的應用場景就是保持咱們應用開啓後僅僅有一個Activity的實例。最典型的樣例就是應用中展現的主頁(Home頁)。
假設用戶在主頁跳轉到其餘頁面,運行屢次操做後想返回到主頁,假設不使用SingleTask模式,在點擊返回的過程當中會屢次看到主頁,這明顯就是設計不合理了。
2. SingleTop模式的運用場景
假設你在當前的Activity中又要啓動同類型的Activity,此時建議將此類型Activity的啓動模式指定爲SingleTop,可以下降Activity的建立,節省內存!
3. 注意:複用Activity時的生命週期回調
這裏還需要考慮一個Activity跳轉時攜帶頁面參數的問題。
因爲當一個Activity設置了SingleTop或者SingleTask模式後,跳轉此Activity出現複用原有Activity的狀況時,此Activity的onCreate方法將不會再次運行。onCreate方法僅僅會在第一次建立Activity時被運行。
而通常onCreate方法中會進行該頁面的數據初始化、UI初始化,假設頁面的展現數據無關頁面跳轉傳遞的參數,則沒必要操心此問題,若頁面展現的數據就是經過getInten() 方法來獲取,那麼問題就會出現:getInten()獲取的一直都是老數據,根本沒法接收跳轉時傳送的新數據!
如下,經過一個樣例來具體解釋:
Manifest.xml
<activity
android:name=".activity.CourseDetailActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
public class CourseDetailActivity extends BaseActivity{
......
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_course_detail_layout);
initData();
initView();
}
//初始化數據
private void initData() {
Intent intent = getIntent();
mCourseID = intent.getStringExtra(COURSE_ID);
}
//初始化UI
private void initView() {
......
}
......
}
以上代碼中的CourseDetailActivity在配置文件裏設置了啓動模式是SingleTop模式,依據上面啓動模式的介紹可得知,當CourseDetailActivity處於棧頂時。再次跳轉頁面到CourseDetailActivity時會直接複用原有的Activity,而且此頁面需要展現的數據是從getIntent()方法得來,但是initData()方法不會再次被調用,此時頁面就沒法顯示新的數據。
固然這樣的狀況系統早就爲咱們想過了,這時咱們需要另一個回調 onNewIntent(Intent intent)方法。此方法會傳入最新的intent,這樣咱們就可以解決上述問題。這裏建議的方法是又一次去setIntent。而後又一次去初始化數據和UI。代碼例如如下所看到的:
/*
* 複用Activity時的生命週期回調
*/
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
initData();
initView();
}
這樣,在一個頁面中可以反覆跳轉並顯示不一樣的內容。
那麼onNewIntent都會在什麼狀況下調用呢?
前提:ActivityA已經啓動過,處於當前應用的Activity堆棧中;
當ActivityA的LaunchMode爲SingleTop時,若是ActivityA在棧頂,且如今要再啓動ActivityA,這時會調用onNewIntent()方法
當ActivityA的LaunchMode爲SingleInstance,SingleTask時,若是已經ActivityA已經在堆棧中,那麼此時會調用onNewIntent()方法
當ActivityA的LaunchMode爲Standard時,因爲每次啓動ActivityA都是啓動新的實例,和原來啓動的不要緊,因此不會調用原來ActivityA的onNewIntent方法
And 生命週期流程
singleInstance:
第一次進入:onCreate onStart
在棧頂再次進入: onNewIntent
不在棧頂再次進入:onNewIntent onRestart onStart
按home鍵再次進入:onRestart onStart
standard:
第一次進入:onCreate onStart
在棧頂再次進入: onCreate onStart
不在棧頂再次進入:onCreate onStart
按home鍵 onPause--onSaveInstanceState--onStop(未勾選「不保留活動‘’)
勾選了的話 onPause--onSaveInstanceState--onStop--onDestroy
再次進入(未勾選「不保留活動‘’): 主activity onNewIntent--onRestart-onStart
非主activity onRestart-onStart
按返回鍵:onPause--onStop--onDestroy (不走save了)從新進入onCreate onStart
singleTop:
第一次進入:onCreate onStart
在棧頂再次進入:onNewIntent
不在棧頂再次進入:onCreate onStart
按home鍵 再次進入:onRestart onStart
singleTask:
第一次進入:onCreate onStart
在棧頂再次進入:onNewIntent
不在棧頂再次進入:onNewIntent onRestart onStart
按home鍵再次進入:onRestart onStart
Activity的四種啓動模式:
1. standard
默認啓動模式,每次激活Activity時都會建立Activity,並放入任務棧中,永遠不會調用onNewIntent()。
2. singleTop
若是在任務的棧頂正好存在該Activity的實例, 就重用該實例,並調用其onNewIntent(),否者就會建立新的實例並放入棧頂(即便棧中已經存在該Activity實例,只要不在棧頂,都會建立實例,而不會調用onNewIntent(),此時就跟standard模式同樣)。
3. singleTask
若是在棧中已經有該Activity的實例,就重用該實例(會調用實例的onNewIntent())。重用時,會讓該實例回到棧頂,所以在它上面的實例將會被移除棧。若是棧中不存在該實例,將會建立新的實例放入棧中(此時不會調用onNewIntent())。
4. singleInstance
在一個新棧中建立該Activity實例,並讓多個應用共享改棧中的該Activity實例。一旦改模式的Activity的實例存在於某個棧中,任何應用再激活改Activity時都會重用該棧中的實例,其效果至關於多個應用程序共享一個應用,無論誰激活該Activity都會進入同一個應用中。
當調用到onNewIntent(intent)的時候,須要在onNewIntent() 中使用setIntent(intent)賦值給Activity的Intent.不然,後續的getIntent()都是獲得老的Intent。