編輯:關於Android編程
分析android Activity啟動流程中ActivityManagerService所扮演的角色
上一篇文章startActivity啟動過程分析,介紹了startActivity是如何一步步創建的,再來看看生命周期的控制。先來一張官方的Activity狀態轉換圖:
Activity的生命周期中只有在以下3種狀態之一,才能較長時間內保持狀態不變。
除此之外,其他狀態都是過渡狀態(或稱為暫時狀態),比如onCreate(),onStart()後很快就會調用onResume()方法。
對於App來說,其Activity的生命周期執行是與系統進程中的ActivityManagerService
有一定關系的,接下來從進程和線程的角度來分析Activity的生命周期,這裡涉及到系統進程和應用進程:
system_server進程是系統進程,Java framework框架的核心載體,裡面運行了大量的系統服務,比如這裡提供ApplicationThreadProxy(簡稱ATP),ActivityManagerService(簡稱AMS),這個兩個服務都運行在system_server進程的不同線程中,由於ATP和AMS都是基於IBinder接口,都是binder線程,binder線程的創建與銷毀都是由binder驅動來決定的。
App進程是應用程序所在進程,主線程主要負責Activity/Service等組件的生命周期以及UI相關操作都運行在這個線程; 另外,每個App進程中至少會有兩個binder線程 ApplicationThread(簡稱AT)和ActivityManagerProxy(簡稱AMP),除了下圖中所示的線程,其實還有很多線程,比如signal catcher線程等。
Binder
用於不同進程之間通信,由一個進程的Binder客戶端向另一個進程的服務端發送事件,比如圖中線程2向線程4發送事務;而handler
用於同一個進程中不同線程的通信,比如圖中線程4向主線程發送消息。
結合圖說說Activity生命周期,比如暫停Activity的流程如下:
線程1
的AMS中調用線程2
的ATP來發送事件;(由於同一個進程的線程間資源共享,可以相互直接調用,但需要注意多線程並發問題)線程2
通過binder將暫停Activity的事件傳輸到App進程的線程4
;線程4
通過handler消息機制,將暫停Activity的消息發送給主線程
;主線程
在looper.loop()中循環遍歷消息,當收到暫停Activity的消息(PAUSE_ACTIVITY
)時,便將消息分發給ActivityThread.H.handleMessage()方法,再經過方法的層層調用,最後便會調用到Activity.onPause()方法。這便是由AMS完成了onPause()控制,那麼同理Activity的其他生命周期也是這麼個流程來進行控制的。
每個App都有一個主線程,大家常說主線程是ActivityThread,其實這個說法是欠妥當的,首先何為線程?一般來說Java層創建線程往往是繼承Thread對象或者實現Runnable,再看看ActivityThread,會發現該對象並沒有繼承任何對象。准確說法ActivityThread是運行在主線程的對象,充當著主線程的職責。
那主線程到底是哪個呢,這個問題涉及到Linux進程與線程的理解,本質上來說大家常說的主線程就是app首次啟動時創建的進程,對於Linux來說進程與線程都是一個task_struct結構體,除了是否有獨立資源,並沒有什麼區別。
那有為何說充當著主線程的職責呢?這是由於進程在創建之初會為主線程創建Looper對象,這個便是用來維護Activity的生命周期。關於更多詳細,可查看我之前在知乎 的一個回答Android中為什麼主線程不會因為Looper.loop()裡的死循環卡死?
Activity的生命周期,都是其他線程通過handler發送消息給主線程,那麼主線程中的ActivityThread
的內部類H
控制整個核心消息處理機制,通過H.handleMessage()
來控制Activity的生命周期,在H類中共定義了50種消息。
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
public static final int HIDE_WINDOW = 106;
public static final int RESUME_ACTIVITY = 107;
public static final int SEND_RESULT = 108;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
public static final int CONFIGURATION_CHANGED = 118;
public static final int CLEAN_UP_CONTEXT = 119;
public static final int GC_WHEN_IDLE = 120;
public static final int BIND_SERVICE = 121;
public static final int UNBIND_SERVICE = 122;
public static final int DUMP_SERVICE = 123;
public static final int LOW_MEMORY = 124;
public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
public static final int RELAUNCH_ACTIVITY = 126;
public static final int PROFILER_CONTROL = 127;
public static final int CREATE_BACKUP_AGENT = 128;
public static final int DESTROY_BACKUP_AGENT = 129;
public static final int SUICIDE = 130;
public static final int REMOVE_PROVIDER = 131;
public static final int ENABLE_JIT = 132;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
public static final int SCHEDULE_CRASH = 134;
public static final int DUMP_HEAP = 135;
public static final int DUMP_ACTIVITY = 136;
public static final int SLEEPING = 137;
public static final int SET_CORE_SETTINGS = 138;
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
public static final int TRIM_MEMORY = 140;
public static final int DUMP_PROVIDER = 141;
public static final int UNSTABLE_PROVIDER_DIED = 142;
public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
public static final int INSTALL_PROVIDER = 145;
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
public static final int CANCEL_VISIBLE_BEHIND = 147;
public static final int BACKGROUND_VISIBLE_BEHIND_CHANGED = 148;
public static final int ENTER_ANIMATION_COMPLETE = 149;
}
主線程每到收到其他線程發送過來的不同的Handler消息,則都會觸發相應的H.handleMessage,下面列舉跟Activity相關的一些常見消息。
一般來說收到消息,都會調用相應handlerxxx方法。比如,LAUNCH_ACTIVITY
則對應handleLaunchActivity
, RESUME_ACTIVITY
則對應handleResumeActivity
等。
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
} break;
case RELAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
} break;
case PAUSE_ACTIVITY:
handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
(msg.arg1&2) != 0);
maybeSnapshot();
break;
case STOP_ACTIVITY_SHOW:
handleStopActivity((IBinder)msg.obj, true, msg.arg2);
break;
case STOP_ACTIVITY_HIDE:
handleStopActivity((IBinder)msg.obj, false, msg.arg2);
break;
case RESUME_ACTIVITY:
handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);
break;
case DESTROY_ACTIVITY:
handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
msg.arg2, false);
break;
...
}
}
先簡單列舉先調用鏈可能涉及的方法(注:並非每次都能同時進入如下調用鏈的每個分支,先大致列舉,後續再展開)
消息: LAUNCH_ACTIVITY
調用鏈
ActivityThread.handleLaunchActivity
ActivityThread.handleConfigurationChanged
ActivityThread.performConfigurationChanged
ComponentCallbacks2.onConfigurationChanged
ActivityThread.performLaunchActivity
LoadedApk.makeApplication
Instrumentation.callApplicationOnCreate
Application.onCreate
Instrumentation.callActivityOnCreate
Activity.performCreate
Activity.onCreate
Instrumentation.callActivityonRestoreInstanceState
Activity.performRestoreInstanceState
Activity.onRestoreInstanceState
ActivityThread.handleResumeActivity
ActivityThread.performResumeActivity
Activity.performResume
Activity.performRestart
Instrumentation.callActivityOnRestart
Activity.onRestart
Activity.performStart
Instrumentation.callActivityOnStart
Activity.onStart
Instrumentation.callActivityOnResume
Activity.onResume
采用縮進方式,來代表方法的調用鏈,相同縮進層的方法代表來自位於同一個調用方法裡。callActivityOnCreate和callActivityonRestoreInstanceState相同層級,代表都是由上一層級的ActivityThread.performLaunchActivity()方法中調用。
App角度
調用鏈過程層層調用,但對上層應用是透明的,App開發者只需要覆寫其中重要的回調函數即可,故此處所說的App角度,便是指App開發者來說可見之處。經過上述的調用鏈,依次會執行下面回調方法。
Application和Activity都實現了ComponentCallbacks2接口;所以Application和Activity會先執行onConfigurationChanged()回調方法。在前面說過onCreate()是過渡狀態,緊跟著會執行handleResumeActivity()方法,然後就進入Resumed狀態。
消息: RESUME_ACTIVITY
調用鏈
ActivityThread.handleResumeActivity
ActivityThread.performResumeActivity
Activity.performResume
Activity.performRestart
Instrumentation.callActivityOnRestart
Activity.onRestart
Activity.performStart
Instrumentation.callActivityOnStart
Activity.onStart
Instrumentation.callActivityOnResume
Activity.onResume
App角度
App處於運行狀態,UI可見。
msg: PAUSE_ACTIVITY
調用鏈
ActivityThread.handlePauseActivity
ActivityThread.performPauseActivity
ActivityThread.callCallActivityOnSaveInstanceState
Instrumentation.callActivityOnSaveInstanceState
Activity.performSaveInstanceState
Activity.onSaveInstanceState
Instrumentation.callActivityOnPause
Activity.performPause
Activity.onPause
App角度
根據saveState是否true決定是否執行callCallActivityOnSaveInstanceState()分支,從而決定是否回調onRestoreInstanceState()方法
msg: STOP_ACTIVITY_HIDE
調用鏈
ActivityThread.handleStopActivity
ActivityThread.performStopActivityInner
ActivityThread.callCallActivityOnSaveInstanceState
Instrumentation.callActivityOnSaveInstanceState
Activity.performSaveInstanceState
Activity.onSaveInstanceState
ActivityThread.performStop
Activity.performStop
Instrumentation.callActivityOnStop
Activity.onStop
updateVisibility
H.post(StopInfo)
AMP.activityStopped
AMS.activityStopped
ActivityStack.activityStoppedLocked
AMS.trimApplications
ProcessRecord.kill
ApplicationThread.scheduleExit
Looper.myLooper().quit()
AMS.cleanUpApplicationRecordLocked
AMS.updateOomAdjLocked
App角度
在停止Activity的過程,會有一個trimApplications()的操作,主要是kill空進程,將當前進程退出loop循環,清理應用的上下文環境,並且更新進程的Adj值。
msg: DESTROY_ACTIVITY
調用鏈
ActivityThread.handleDestroyActivity
ActivityThread.performDestroyActivity
Instrumentation.callActivityOnPause
Activity.performStop()
Instrumentation.callActivityOnDestroy
Activity.performDestroy
Window.destroy
Activity.onDestroy
AMP.activityDestroyed
AMS.activityDestroyed
ActivityStack.activityDestroyedLocked
ActivityStackSupervisor.resumeTopActivitiesLocked
ActivityStack.resumeTopActivityLocked
ActivityStack.resumeTopActivityInnerLocked
App角度
銷毀應用後,會查看第一個沒有結束的Activity,用於顯示在最頂層界面,當不存在未結束的Activity時,則顯示Launcher界面,即主界面。
msg: NEW_INTENT
(打開已經處於棧頂的Activity,則會發送給NEW_INTENT消息給主線程)
調用鏈
ActivityThread.handleNewIntent
performNewIntents
Instrumentation.callActivityOnPause
Activity.performPause
Activity.onPause
deliverNewIntents
Instrumentation.callActivityOnNewIntent
Activity.onNewIntent
Activity.performResume
Activity.performRestart
Instrumentation.callActivityOnRestart
Activity.onRestart
Activity.performStart
Instrumentation.callActivityOnStart
Activity.onStart
Instrumentation.callActivityOnResume
Activity.onResume
App角度
本文主要是概括性講述Activity的調用過程,後續會再從源碼角度進一步細說Activity生命周期,敬請期待。
從本文開始為大家制作一個Android個人理財工具,並把整個開發過程記錄下來,與大家
先看看電影票在線選座功能實現的效果圖: 界面比較粗糙,主要看原理。這個界面主要包括以下幾部分 1、座位 2、左邊的排數 3、左上方的縮略圖 4、縮略圖中的紅色區域 5、手
今天主要添加了一個換膚的功能,可以切換6種不同的背景,即點擊“換膚”按鈕可以實現切換背景圖片。 這個我在網上搜了好長時間,最終最靠譜和好理解的應該是下面這個鏈接裡的方法:
應用開發中經常會有從數據庫中讀取數據顯示,然後選中多條、全部記錄並且刪除的需求。在做定制系統聯系人的時候也遇到這樣的需求,下面寫個簡單的通過ListView和CheckB