一.簡介
???????Activity是Android組件中最基本也是最為常見用的四大組件(Activity废菱,Service服務蜂筹,Content Provider內(nèi)容提供者力细,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實例已經(jīng)存在于棧頂崭孤,那么再次啟動這個activity的時候类嗤,不會重新創(chuàng)建實例,而是重用位于棧頂?shù)哪莻€實例裳瘪,并且會調(diào)用實例的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)中已經(jīng)存在這樣一個實例溢十,就會將這個實例調(diào)度到任務棧的棧頂垮刹,并清除它當前所在任務中位于它上面的所有的activity;如果這個已存在的任務中不存在一個要啟動的Activity的實例张弛,則在這個任務的頂端啟動一個實例荒典;若這個任務不存在酪劫,則會啟動一個新的任務,在這個新的任務中啟動這個singleTask模式的Activity的一個實例寺董。
d.singleInstance:
???????以singleInstance模式啟動的Activity具有全局唯一性覆糟,即整個系統(tǒng)中只會存在一個這樣的實例,如果在啟動這樣的Activiyt時遮咖,已經(jīng)存在了一個實例搪桂,那么會把它所在的任務調(diào)度到前臺,重用這個實例盯滚。
???????以singleInstance模式啟動的Activity具有獨占性踢械,即它會獨自占用一個任務,被他開啟的任何activity都會運行在其他任務中(官方文檔上的描述為魄藕,singleInstance模式的Activity不允許其他Activity和它共存在一個任務中)内列。
???????被singleInstance模式的Activity開啟的其他activity,能夠開啟一個新任務背率,但不一定開啟新的任務话瞧,也可能在已有的一個任務中開啟,受條件的限制寝姿,這個條件是:當前系統(tǒng)中是不是已經(jīng)有了一個activity B的taskAffinity屬性指定的任務交排。
三.Activity管理
???????涉及到Activity啟動,就不得不說一下Activity的管理饵筑,Activity是以什么方式及被什么類來進行管理的埃篓,涉及的類主要如下:
a.ActivityRecord:
???????歷史棧中的一個條目,代表一個activity根资。ActivityRecord中的成員變量task表示其所在的TaskRecord架专,ActivityRecord與TaskRecord建立了聯(lián)系。
b.TaskRecord:
???????內(nèi)部維護一個 ArrayList<ActivityRecord> 用來保存ActivityRecord玄帕,TaskRecord中的mStack表示其所在的ActivityStack部脚,TaskRecord與ActivityStack建立了聯(lián)系。
c.ActivityStack:
???????內(nèi)部維護了一個 ArrayList<TaskRecord> 裤纹,用來管理TaskRecord委刘,ActivityStack中持有ActivityStackSupervisor對象,由ActivityStackSupervisor創(chuàng)建鹰椒。
d.ActivityStackSupervisor:
???????負責所有ActivityStack的管理锡移。內(nèi)部管理了mHomeStack、mFocusedStack和mLastFocusedStack三個Activity棧吹零。其中罩抗,mHomeStack管理的是Launcher相關的Activity棧;mFocusedStack管理的是當前顯示在前臺Activity的Activity棧灿椅;mLastFocusedStack管理的是上一次顯示在前臺Activity的Activity棧套蒂。
e.ActivityThread:
???????ActivityThread 運行在UI線程(主線程)钞支,App的真正入口。
f.ApplicationThread:
???????用來實現(xiàn)AMS和ActivityThread之間的交互操刀。
g.Instrumentation:
???????負責調(diào)用Activity和Application生命周期烁挟。
四.Activity狀態(tài)保存
???????當一個Activity未被主動關閉,即“被動關閉”時骨坑,可能需要系統(tǒng)給用戶提供保持一些狀態(tài)的入口撼嗓。
a.調(diào)用入口
???????前面說的入口就是:Activity提供了onSaveInstanceState()方法,該方法是Activity在關閉前保存狀態(tài)的核心方法欢唾。
b.調(diào)用場景
???????前面提到“被動關閉”且警,如果是主動關閉那么就不會調(diào)用,比如:按back鍵礁遣、調(diào)用finish()等斑芜,那么"被動關閉"的場景有哪些呢?下面給列舉一下:
場景 | 具體描述 |
---|---|
從當前activity啟動新activity后 | 當前activity會調(diào)用onSaveInstanceState() |
屏幕切換祟霍,橫屏切豎屏及豎屏切橫屏 | 切換時杏头,系統(tǒng)會先銷毀activity,切換后系統(tǒng)再創(chuàng)建新的activity沸呐, 所以會調(diào)用onSaveInstanceState() |
按HOME鍵后 | 按下home鍵醇王,會啟動新的應用,當前activity會調(diào)用onSaveInstanceState() |
關閉屏幕顯示 | 進入熄屏界面崭添,當前activity會調(diào)用onSaveInstanceState() |
切換白天黑夜模式 | 當未配置configChange時寓娩,切換白天黑夜模式,當前activity會調(diào)用onSaveInstanceState() |
c.調(diào)用時機
???????肯定在調(diào)用onStop()前被調(diào)用滥朱,但不保證在onPause()前 / 后根暑,一般是在onPause()后調(diào)用。
d.使用方式
???????當需要保持狀態(tài)時徙邻,在onSaveInstanceState()內(nèi)執(zhí)行以下邏輯:
@Override
protected void onSaveInstanceState(Bundle outState) {
//調(diào)用父類方法幫助UI存儲狀態(tài)
super.onSaveInstanceState(outState);
outState.putInt(ActionUtils.SRCDISPLAY, mSrcDisplay);
outState.putInt("Control_State", mControlState);
}
???????當需要恢復時,在onCreate()內(nèi)部執(zhí)行以下邏輯:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//首次啟動時畸裳,獲取Intent內(nèi)部傳入的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默認實現(xiàn):onSaveInstanceState()怖糊,即UI的任何改變都會自動的存儲和在activity重新創(chuàng)建的時候自動的恢復(只有在為該UI提供了唯一ID后才起作用)帅容;
???????若需復寫該方法從而存儲額外的狀態(tài)信息時,應先調(diào)用父類的onSaveInstanceState()(因為默認的onSaveInstanceState()幫助UI存儲它的狀態(tài))伍伤;
???????只使用該方法記錄Activity的瞬間狀態(tài)(UI的狀態(tài))并徘,而不是去存儲持久化數(shù)據(jù),因為onSaveInstanceState()調(diào)用時機不確定性扰魂;可使用 onPause()[一定會執(zhí)行]存儲持久化數(shù)據(jù)麦乞;
四.Activity狀態(tài)恢復
a.調(diào)用入口
???????Activity提供了onRestoreInstanceState()方法蕴茴,該方法是Activity在重新創(chuàng)建后恢復之前保存狀態(tài)的核心方法。
b.調(diào)用場景
???????若被動關閉了Activity姐直,即調(diào)用了onSaveInstanceState()倦淀,那么下次啟動時會調(diào)用onRestoreInstanceState()。
c.調(diào)用時機
???????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()不一定 成對被調(diào)用
???????如:當正在顯示Activity A時撞叽,用戶按下HOME鍵回到主界面,然后用戶緊接著又返回到Activity A插龄,此時Activity A一般不會因為內(nèi)存的原因被系統(tǒng)銷毀愿棋,故Activity A的onRestoreInstanceState()不會被執(zhí)行;
???????針對以上情況均牢,onSaveInstanceState保持的參數(shù)可以選擇在onCreate()內(nèi)部進行解析使用初斑,因為onSaveInstanceState的bundle參數(shù)會傳遞到onCreate方法中,可選擇在onCreate()中做數(shù)據(jù)還原膨处。
???????至此:Activity的啟動模式及Activity的狀態(tài)保持及恢復介紹完畢见秤。