如題所示,Activity是如何顯示出來的呢?簡單,調用startActivity就能夠啓動目標Activity了。很方便,但其實也隱藏了不少細節。startActivity後發生了什麼事?怎麼一個簡單的接口就能啓動一個界面,且該界面所在進程還未啓動過。本篇文章承接《我是怎麼把一個個App進程建立起來的》,描述接下來發生的事。java
想要啓動一個Activity,首先得啓動它的進程,由AMS將啓動進程的需求發給Zygote,由這位大佬fork出一個進程,而後啓動。啓動的入口是ActivityThread類的main方法,分析從這裏開始。android
咱們總說UI的刷新是在主線程進行的,但卻沒找到相關主線程的痕跡。今天它來了,UI主線程就在此處。這裏列出main方法關鍵代碼進行分析。微信
//frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
....
//①建立一個Loop實體,用於消息處理
Looper.prepareMainLooper();
....
//②建立ActivityThread對象,而後在attach方法中會完成Application對象的初始化,而後調用Application的onCreate()方法
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
//③獲取Handler對象
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
....
④啓動Loop,表示能夠接收Handler發過來的消息
Looper.loop();
}
複製代碼
如上按照註釋,main方法中作的事情主要有三件,建立Loop實體,獲取Handler,用於消息處理,建立ActivityThread對象,而後調用attach方法完成Application的初始化。咱們先看看attach方法作了什麼事:app
//frameworks/base/core/java/android/app/ActivityThread.java
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
//啓動JIT編譯器,開始編譯
ensureJitEnabled();
}
});
//設置進程名
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// Watch for getting close to heap limit.
//看app進程內存狀況,若是太大則釋放內存
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
//使用的內存超過最大內存的四分之三,則請求釋放內存
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
} else {
....
}
....
}
複製代碼
應用進程調用的attach方法傳入的第一個參數爲false,因此咱們這裏主要看false分支的代碼就行了。這裏面主要作了以下幾件事:框架
1.啓動JIT編譯器,開始編譯; //這是啥,我也不清楚,後面再找時間補充學習
2.設置進程名;
3.經過ActivityManager獲取AMS服務代理對象IActivityManager,經過它來完成一次跨進程操做,主要是用來綁定ApplicationThread對象;
4.內存使用檢測,若發現使用的內存超過最大內存的四分之三,則申請進行內存釋放;
複製代碼
這裏還看不出Activity的顯示相關,還須要進入AMS進行查看attachApplication方法:ide
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
複製代碼
這裏又封裝了一層,調用attachApplicationLocked方法:oop
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
....
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
....
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
....
}
複製代碼
attachApplicationLocked方法比較長,在進行bind以前,前面部分在進行一些app的準備工做。一切準備就緒,會回調ActivityThread對象自己的bindApplication方法進行綁定。接着若是這個進程有待顯示的Activity在棧頂,則會調用ActivityStackSupervisor類的attachApplicationLocked方法進行顯示。post
/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
....
try {
if (realStartActivityLocked(activity, app,
top == activity /* andResume */, true /* checkConfig */)) {
didSomething = true;
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting activity "
+ top.intent.getComponent().flattenToShortString(), e);
throw e;
}
....
}
複製代碼
最終調用realStartActivityLocked方法:學習
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, mService.isNextTransitionForward(),
profilerInfo));
...
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
...
}
複製代碼
該方法建立了一個加載Activity的事務,等一切狀態就緒,調用ClientLifecycleManager類的scheduleTransaction方法開始處理事務。ui
/frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
transaction.schedule();
if (!(client instanceof Binder)) {
// If client is not an instance of Binder - it's a remote call and at this point it is
// safe to recycle the object. All objects used for local calls will be recycled after
// the transaction is executed on client in ActivityThread.
transaction.recycle();
}
}
複製代碼
最終調用了ClientTransaction對象的schedule方法,ClientTransaction對象在上個方法中被建立,即上述所說的事務。回到ClientTransaction的實現:
frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
複製代碼
mClient又是什麼?這是一個IApplicationThread類型的變量,該變量在建立事務的時候被賦值:
public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
if (instance == null) {
instance = new ClientTransaction();
}
instance.mClient = client;
instance.mActivityToken = activityToken;
return instance;
}
複製代碼
兜兜轉轉,咱們須要返回realStartActivityLocked方法中查看client究竟是個啥:
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
複製代碼
建立啓動Activity事務時,傳入了一個IApplicationThread引用,這只是個代理,真正的實如今ApplicationThread類中,這是ActivityThread類的內部類,看看具體實現:
frameworks/base/core/java/android/app/ActivityThread.java
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
複製代碼
這裏直接調用ActivityThread父類的方法,發出一個處理事務的msg:
frameworks/base/core/java/android/app/ClientTransactionHandler.java
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
複製代碼
具體處理仍是ActivityThread中:
public void handleMessage(Message msg) {
...
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
...
}
複製代碼
還未到終點,又是一個execute方法,進入看看:
frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java
public void execute(ClientTransaction transaction) {
final IBinder token = transaction.getActivityToken();
log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
log("End resolving transaction");
}
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
....
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
....
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
....
}
....
}
複製代碼
這裏若是直接進入到ClientTransactionItem類中,會發現並沒有具體實現,這就是個抽象類。item是從事務中獲取的回調,還記得在realStartActivityLocked方法中建立事務的過程麼?建立了事務以後,還作了一件事:
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, mService.isNextTransitionForward(),
profilerInfo));
複製代碼
這裏增長了一個LaunchActivityItem類的回調,而LaunchActivityItem正是繼承ClientTransactionItem類,因此這裏的execute方法應該是在LaunchActivityItem類中實現:
frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
複製代碼
又回調了ActivityThread(繼承ClientTransactionHandler抽象類)的handleLaunchActivity方法:
frameworks/base/core/java/android/app/ActivityThread.java
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
....
final Activity a = performLaunchActivity(r, customIntent);
....
}
複製代碼
真正啓動Activity的核心即將到來:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
....
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
....
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
....
mInstrumentation.callActivityOnPostCreate(activity, r.state);
....
}
複製代碼
這裏主要作了三件事:
1.經過Instrumentation類建立出activity;
2.調用activity的attach方法建立窗口,爲onCreate方法作準備;
3.經過callActivityOnPostCreate方法,最終調用activity的onCreate方法,在該方法中,經過setContentView方法將activity具體的view樹加載到窗口。
複製代碼
到了這裏,Activity還未真正顯示出來,只是該作的準備都作好了,下一步就是將具體的view加載到窗口中進行顯示。這部份內容留到下一章節分析。
Activity的啓動確實複雜,到如今也只是大概捋了個流程,並無深刻理解。在本章節中,大概分析了startActivity的流程。若是Activity所在進程是首次啓動,則還須要經過AMS向Zygote進程發起進程建立的需求,而後在建立出來的子進程中,使用反射的方法,找到App的ActivityThread的main方法,並啓動運行。
先掌握大概的流程框架,再逐步深刻了解各個模塊。下一個章節分析view的加載。
我在微信公衆號也有寫文章,更新比較及時,有興趣者能夠掃描以下二維碼,或者微信搜索【Android系統實戰開發】,關注有驚喜哦!