一.簡介
Activity是Android組件中最基本也是最為常見用的四大組件(Activity,Service服務,Content Provider內容提供者或听,BroadcastReceiver廣播接收器)之一 。
Activity是一個應用程序組件每界,提供一個屏幕,用戶可以用來交互為了完成某項任務。
Activity中所有操作都與用戶密切相關,是一個負責與用戶交互的組件仿滔,可以通過setContentView(View)來顯示指定控件。
在一個android應用中扰付,一個Activity通常就是一個單獨的屏幕堤撵,它上面可以顯示一些控件也可以監(jiān)聽并處理用戶的事件做出響應仁讨。Activity之間通過Intent進行通信羽莺。
關于Activity啟動流程請參考之前的文章Android activity啟動流程分析
二.啟動模式
activity有四種啟動模式,分別為standard洞豁,singleTop盐固,singleTask,singleInstance丈挟。如果要使用這四種啟動模式刁卜,必須在manifest文件中<activity>標簽中的launchMode屬性中配置。
a.standard
標準的默認啟動模式曙咽,這種模式下activity可以被多次實例化蛔趴,即在一個task中可以存在多個activity,每一個activity會處理一個intent對象例朱,(在A中再次啟動A孝情,會存在后面的A在前面的A上面,當前task會存在兩個activity的實例對象)
b.singleTop
如果一個singleTop模式啟動的activity實例已經存在于棧頂洒嗤,那么再次啟動這個activity的時候箫荡,不會重新創(chuàng)建實例,而是重用位于棧頂的那個實例渔隶,并且會調用實例的onNewIntent()方法將Intent對象傳遞到這個實例中羔挡,如果實例不位于棧頂,會創(chuàng)建新的實例间唉。
c.singleTask:
啟動模式設置為singleTask绞灼,framework在啟動該activity時只會把它標示為可在一個新任務中啟動,至于是否在一個新任務中啟動呈野,還要受其他條件的限制低矮,即taskAffinity屬性。
taskAffinity:默認情況下际跪,一個應用中的所有activity具有相同的taskAffinity商佛,即應用程序的包名喉钢。我們可以通過設置不同的taskAffinity屬性給應用中的activity分組,也可以把不同的應用中的activity的taskAffinity設置成相同的值良姆,當兩個不同應用中的activity設置成相同的taskAffinity時肠虽,則兩個activity會屬于同一個TaskRecord。
在啟動一個singleTask的Activity實例時玛追,如果系統(tǒng)中已經存在這樣一個實例税课,就會將這個實例調度到任務棧的棧頂,并清除它當前所在任務中位于它上面的所有的activity痊剖;如果這個已存在的任務中不存在一個要啟動的Activity的實例韩玩,則在這個任務的頂端啟動一個實例;若這個任務不存在陆馁,則會啟動一個新的任務找颓,在這個新的任務中啟動這個singleTask模式的Activity的一個實例。
d.singleInstance:
以singleInstance模式啟動的Activity具有全局唯一性叮贩,即整個系統(tǒng)中只會存在一個這樣的實例击狮,如果在啟動這樣的Activiyt時,已經存在了一個實例益老,那么會把它所在的任務調度到前臺彪蓬,重用這個實例。
以singleInstance模式啟動的Activity具有獨占性捺萌,即它會獨自占用一個任務档冬,被他開啟的任何activity都會運行在其他任務中(官方文檔上的描述為,singleInstance模式的Activity不允許其他Activity和它共存在一個任務中)桃纯。
被singleInstance模式的Activity開啟的其他activity酷誓,能夠開啟一個新任務,但不一定開啟新的任務慈参,也可能在已有的一個任務中開啟呛牲,受條件的限制,這個條件是:當前系統(tǒng)中是不是已經有了一個activity B的taskAffinity屬性指定的任務驮配。
三.Activity管理
涉及到Activity啟動娘扩,就不得不說一下Activity的管理,Activity是以什么方式及被什么類來進行管理的壮锻,涉及的類主要如下:
a.ActivityRecord:
歷史棧中的一個條目琐旁,代表一個activity。ActivityRecord中的成員變量task表示其所在的TaskRecord猜绣,ActivityRecord與TaskRecord建立了聯系灰殴。
b.TaskRecord:
內部維護一個 ArrayList<ActivityRecord> 用來保存ActivityRecord,TaskRecord中的mStack表示其所在的ActivityStack掰邢,TaskRecord與ActivityStack建立了聯系牺陶。
c.ActivityStack:
內部維護了一個 ArrayList<TaskRecord> 伟阔,用來管理TaskRecord,ActivityStack中持有ActivityStackSupervisor對象掰伸,由ActivityStackSupervisor創(chuàng)建皱炉。
d.ActivityStackSupervisor:
負責所有ActivityStack的管理。內部管理了mHomeStack狮鸭、mFocusedStack和mLastFocusedStack三個Activity棧合搅。其中,mHomeStack管理的是Launcher相關的Activity棧歧蕉;mFocusedStack管理的是當前顯示在前臺Activity的Activity棧灾部;mLastFocusedStack管理的是上一次顯示在前臺Activity的Activity棧。
e.ActivityThread:
ActivityThread 運行在UI線程(主線程)惯退,App的真正入口赌髓。
f.ApplicationThread:
用來實現AMS和ActivityThread之間的交互。
g.Instrumentation:
負責調用Activity和Application生命周期蒸痹。
四.Activity狀態(tài)保存
當一個Activity未被主動關閉春弥,即“被動關閉”時,可能需要系統(tǒng)給用戶提供保持一些狀態(tài)的入口叠荠。
a.調用入口
前面說的入口就是:Activity提供了onSaveInstanceState()方法,該方法是Activity在關閉前保存狀態(tài)的核心方法扫责。
b.調用場景
前面提到“被動關閉”榛鼎,如果是主動關閉那么就不會調用,比如:按back鍵鳖孤、調用finish()等者娱,那么"被動關閉"的場景有哪些呢?下面給列舉一下:
場景 | 具體描述 |
---|---|
從當前activity啟動新activity后 | 當前activity會調用onSaveInstanceState() |
屏幕切換苏揣,橫屏切豎屏及豎屏切橫屏 | 切換時黄鳍,系統(tǒng)會先銷毀activity,切換后系統(tǒng)再創(chuàng)建新的activity平匈, |
所以會調用onSaveInstanceState() | |
按HOME鍵后 | 按下home鍵框沟,會啟動新的應用,當前activity會調用onSaveInstanceState() |
關閉屏幕顯示 | 進入熄屏界面增炭,當前activity會調用onSaveInstanceState() |
切換白天黑夜模式 | 當未配置configChange時忍燥,切換白天黑夜模式,當前activity會調用onSaveInstanceState() |
c.調用時機
肯定在調用onStop()前被調用隙姿,但不保證在onPause()前 / 后梅垄,一般是在onPause()后調用。
d.使用方式
當需要保持狀態(tài)時输玷,在onSaveInstanceState()內執(zhí)行以下邏輯:
@Override
protected void onSaveInstanceState(Bundle outState) {
//調用父類方法幫助UI存儲狀態(tài)
super.onSaveInstanceState(outState);
outState.putInt(ActionUtils.SRCDISPLAY, mSrcDisplay);
outState.putInt("Control_State", mControlState);
}
當需要恢復時队丝,在onCreate()內部執(zhí)行以下邏輯:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//首次啟動時靡馁,獲取Intent內部傳入的bundle
if (savedInstanceState == null) {
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
mSrcDisplay = bundle.getInt(ActionUtils.SRCDISPLAY);
//savedInstanceState不為空,說明執(zhí)行了onSaveInstanceState()机久,直接獲取對應的狀態(tài)
} else {
mSrcDisplay = savedInstanceState.getInt(ActionUtils.SRCDISPLAY);
mControlState = savedInstanceState.getInt("Control_State");
}
}
布局每個View默認實現:onSaveInstanceState()奈嘿,即UI的任何改變都會自動的存儲和在activity重新創(chuàng)建的時候自動的恢復(只有在為該UI提供了唯一ID后才起作用);
若需復寫該方法從而存儲額外的狀態(tài)信息時吞加,應先調用父類的onSaveInstanceState()(因為默認的onSaveInstanceState()幫助UI存儲它的狀態(tài))裙犹;
只使用該方法記錄Activity的瞬間狀態(tài)(UI的狀態(tài)),而不是去存儲持久化數據衔憨,因為onSaveInstanceState()調用時機不確定性叶圃;可使用 onPause()[一定會執(zhí)行]存儲持久化數據;
四.Activity狀態(tài)恢復
a.調用入口
Activity提供了onRestoreInstanceState()方法践图,
該方法是Activity在重新創(chuàng)建后恢復之前保存狀態(tài)的核心方法掺冠。
b.調用場景
若被動關閉了Activity,即調用了onSaveInstanceState()码党,那么下次啟動時會調用onRestoreInstanceState()德崭。
c.調用時機
onCreate()--->onStart()--->onRestoreInstanceState()--->onResume()
d.使用方式
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mSrcDisplay = savedInstanceState.getInt(ActionUtils.SRCDISPLAY);
mControlState = savedInstanceState.getInt("Control_State");
}
注意:onSaveInstanceState()、onRestoreInstanceState()不一定 成對被調用
如:當正在顯示Activity A時揖盘,用戶按下HOME鍵回到主界面眉厨,然后用戶緊接著又返回到Activity A,此時Activity A一般不會因為內存的原因被系統(tǒng)銷毀兽狭,故Activity A的onRestoreInstanceState()不會被執(zhí)行憾股;
針對以上情況,onSaveInstanceState保持的參數可以選擇在onCreate()內部進行解析使用箕慧,因為onSaveInstanceState的bundle參數會傳遞到onCreate方法中服球,可選擇在onCreate()中做數據還原。
至此:Activity的啟動模式及Activity的狀態(tài)保持及恢復介紹完畢颠焦。
作者:雷濤賽文
鏈接:http://www.reibang.com/p/765c7b6e6bc7
來源:簡書
轉載以備查閱