不知道你們有沒有想過這樣一個問題,平常開發中最經常使用到的經過 startActivity()
喚起一個新的 Activity,所建立的 Activity 對象到底被誰持有引用了?新啓動的 Activity 對象在其生命週期中理應是一直被持有引用,否則系統 gc 的時候就會被回收掉,那麼其中的引用關係是怎樣的呢?java
爲了搞清楚整個問題,筆者便開始了翻找源碼之旅(Android Q),首先得弄清楚 Activity 實例是如何被建立的。android
Activity 的啓動是一個跨進程通訊的過程,對客戶端而言,Activity 的建立會回調到 ActivityThread 中的 handleLaunchActivity()
方法:app
frameworks/base/core/java/android/app/ActivityThread.java:ide
@Override
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {
···
final Activity a = performLaunchActivity(r, customIntent);
···
return a;
}
複製代碼
接着在 performLaunchActivity()
方法裏找到了 Acitivity 實例的建立:oop
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
···
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
// 註解1:經過 ClassLoader 以及目標 Activity 的類名來建立新的 Activity 實例
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
···
} ···
}
複製代碼
Activity 相關的建立工做交由給了 Instrumentation 類處理:this
frameworks/base/core/java/android/app/Instrumentation.java:spa
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
String pkg = intent != null && intent.getComponent() != null
? intent.getComponent().getPackageName() : null;
return getFactory(pkg).instantiateActivity(cl, className, intent);
}
複製代碼
最終的建立工做由進一步交由工廠類 AppComponentFactory 實現:3d
frameworks/base/core/java/android/app/AppComponentFactory.java:code
public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className, @Nullable Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (Activity) cl.loadClass(className).newInstance();
}
複製代碼
到這裏,Activity 對象的建立過程已經很清晰了:經過 ClassLoader 對象以及類名獲取到目標 Activity 的 Class 對象, 再調用 Class 對象的 newInstance()
方法建立了實例。component
用圖形關係表示以下:
在清楚了 Activity 對象的建立過程後,讓咱們回到一開始的 ActivityThread 的 performLaunchActivity()
方法中,接着往下看:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
···
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
···
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
···
if (activity != null) {
···
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,
r.assistToken);
···
// 註解2:ActivityClientRecord 對象持有 Activity 實例的引用
r.activity = activity;
}
r.setState(ON_CREATE);
// 註解3:將 ActivityClientRecord 對象添加到 mActivities 集合中
synchronized (mResourcesManager) {
mActivities.put(r.token, r);
}
} ···
return activity;
}
複製代碼
在這裏,咱們彷佛找到了想要的答案:
新建的 Activity 對象會被傳進來的 ActivityClientRecord 對象所持有,接着該 ActivityClientRecord 對象會被添加到一個名爲 mActivities
的集合當中所持有。
ActivityClientRecord 是 ActivityThread 的一個靜態內部類,用於記錄 Activity 相關的信息。其對象的建立過程能夠在 LaunchActivityItem 類(Api 28 以後)中找到:
frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java:
@Override
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, mAssistToken);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
複製代碼
再來看一下這個 mActivities
集合:
frameworks/base/core/java/android/app/ActivityThread.java
:
···
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
···
複製代碼
mActivities
是一個 map 集合,爲 ActivityThread 對象的一個成員變量。既然是一個集合,天然也能夠在 Activity 銷燬方法回調中找到移除集合內元素的操做:
/** Core implementation of activity destroy call. */
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) {
ActivityClientRecord r = mActivities.get(token);
···
synchronized (mResourcesManager) {
mActivities.remove(token);
}
StrictMode.decrementExpectedActivityCount(activityClass);
return r;
}
複製代碼
圖形關係表示以下:
既然 Activity 的對象是間接被 ActivityThread 對象所持有引用,那麼該 ActivityThread 對象理應是單例的形式存在,那麼該單例 ActivityThread 對象又是如何被建立以及持有的呢?
一個新的應用進程建立時,會調用 ActivityThread 的靜態主方法 main()
,在這裏,咱們找到了答案:
frameworks/base/core/java/android/app/ActivityThread.java:
···
// 註解 4:靜態的 ActivityThread 成員變量,用於實現單例
private static volatile ActivityThread sCurrentActivityThread;
···
// 註解 5: ActivityThread 的主方法入口,由 RuntimeInit 調用
public static void main(String[] args) {
···
Looper.prepareMainLooper();
···
// 註解 6: 新建一個 ActivityThread 對象
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
···
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
···
private void attach(boolean system, long startSeq) {
// 註解 7: ActivityThread 對象由靜態成員變量所引用
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
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();
}
···
} ···
}
複製代碼
由上面的代碼可知,一個新的應用進程建立時,main()
方法裏新建一個 ActivityThread 對象賦予給 ActivityThread 類的一個靜態成員變量 sCurrentActivityThread
,從而造成一個應用進程對應一個 ActivityThread 對象(單例) 的關係。
每個新啓動的 Activity,其對象實例經過 Class 類的 newInstance
方法建立後,被包裹在一個 ActivityClientRecord 對象中而後添加到進程惟一的 ActivityThread 對象的成員變量 mActivitys 裏。換言之,Activity 對象的持有和釋放都是由 ActivityThread 來管理的。
最後,筆者想額外重申兩點:
- 源碼中,Activity 對象會在多個方法都有傳遞關係,比較複雜,筆者才疏學淺,可能會漏掉一些別的重要的引用關係沒有分析,歡迎你們指正。
- 上文的 framework 源碼用的是截稿前最新的 Android Q 版本,不一樣的 Android 系統版本這部分相關的源碼都會有所改動,不能詳細一一對比分析,望你們見諒。
本次的分享就到這啦,喜歡的話能夠點個贊 👍 或關注唄。若有錯誤的地方歡迎你們在評論裏指出。