Android 之ActivityThead、ActivityManagerService 與activity的管理和建立
android中,Activity是四大元件中比較重要的一個(當然其他的也比較重要),那麼android中是怎樣管理這些activity的?應用的程序和主執行緒是怎麼建立的,應用的訊息迴圈又是在什麼時候建立的?在這篇文章中將詳細介紹:
先來看下涉及到的類,通過以下類圖對整體先有個大概的印象:
ActivityThread:
ActivityThread主要用來啟動應用程式的主執行緒,並且管理在應用端跟使用者打交道的activity。在應用端的activity資訊全部被儲存在ActivityThread的成員變數mActivities中。
-
final HashMap<IBinder, ActivityRecord> mActivities=
也就是說,在mActivities中,記錄了應用程式建立的所有activity例項記錄,對應的是ActivityRecord。
ActivityThread是怎麼啟動應用程式的呢?ActivityThread中有一個main函式,在這個裡面,將啟動應用程式並建立訊息迴圈。在之前也介紹過,系統會為主執行緒自動建立訊息迴圈。
-
/*** 應用程式的啟動入口 . ,主執行緒在啟動的時候系統會自動建立訊息迴圈機制。*/publicstaticfinalvoid main(String[] args) { SamplingProfilerIntegration.start(); Process.setArgV0(
在建立訊息迴圈之前,會通過thread.attach(false)來初始化應用程式的執行環境,並建立activityThread和ActivityManagerService之間的橋mAppThread, mAppThread是IApplicationThread的一個例項。
- android.ddm.DdmHandleAppName.setAppName("<pre-initialized>"); RuntimeInit.setApplicationObject(mAppThread.asBinder()); IActivityManager mgr = ActivityManagerNative.getDefault(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { }
注意:每個應用程式對應著一個ActivityThread例項,應用程式由ActivityThread.main開啟訊息迴圈。每個應用程式同時也對應著一個ApplicationThread物件。該物件是activityThread和ActivityManagerService之間的橋樑。
在attach中還做了一件事情,就是通過代理呼叫attachApplication,並利用binder的transact機制,在ActivityManagerService中建立了ProcessRecord資訊。
之後通過該ProcessRecord就可以獲得該ActivityThread中的所有ActivityRecord記錄。下面會介紹。
ActivityManagerService:
在ActivityManagerService中,也有一個用來管理activity的地方:mHistory棧,這個mHistory棧裡存放的是服務端的activity記錄HistoryActivity(class HistoryRecord extendsIApplicationToken.Stub)。處於棧頂的就是當前running狀態的activity。
我們來看一下Activity的startActivity方法的請求過程:
從該時序圖中可以看出,Activity.startActivity()方法最終是通過代理類和Binder機制,在ActivityManagerService.startActivity方法中執行的。
那麼在ActivityManagerService的startActivity中,主要做了那些事情?我們來看下里面比較重要的程式碼段:
- 根據activity、ProcessRecord等資訊建立HistoryRecord例項r
- HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,intent, resolvedType, aInfo, mConfiguration,resultRecord, resultWho, requestCode, componentSpecified);
- 把r加入到mHistory中。
- mHistory.add(addPos, r);
- app.thread.scheduleLaunchActivity(new Intent(r.intent), r,System.identityHashCode(r), r.info, r.icicle, results, newIntents, !andResume, isNextTransitionForward());
涉及的主要類圖:
再來看下ApplicationThread中的scheduleLaunchActivity方法:
- public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) { ActivityRecord r = new ActivityRecord(); r.token = token; r.ident = ident; r.intent = intent; r.activityInfo = info; r.state = state; r.pendingResults = pendingResults; r.pendingIntents = pendingNewIntents; r.startsNotResumed = notResumed; r.isForward = isForward; queueOrSendMessage(H.LAUNCH_ACTIVITY, r); }
在這個裡面主要是根據服務端返回回來的資訊建立客戶端activity記錄ActivityRecord. 並通過Handler傳送訊息到訊息佇列,進入訊息迴圈。在ActivityThread.handleMessage()中處理訊息。最終在handleLaunchActivity方法中把ActivityRecord記錄加入到mActivities(mActivities.put(r.token,r))中,並啟動activity(涉及到window、view、windowManager,詳情請看handleResumeActivity()方法和上一篇關於window、WindowManager的介紹)
總結:
- 在客戶端和服務端分別有一個管理activity的地方,服務端是在mHistory中,處於mHistory棧頂的就是當前處於running狀態的activity,客戶端是在mActivities中。
- 在startActivity時,首先會在ActivityManagerService中建立HistoryRecord,並加入到mHistory中,然後通過scheduleLaunchActivity在客戶端建立ActivityRecord記錄並加入到mActivities中。最終在ActivityThread發起請求,進入訊息迴圈,完成activity的啟動和視窗的管理等