StartActivity () is the most common way to invoke a new Activity. Who holds the reference to the created Activity object? A newly started Activity object is supposed to hold a reference throughout its life, otherwise it will be recycled during system gc. What about the reference relationship?
To figure out the whole issue, I started a source search tour (Android Q), first figuring out how the Activity instance was created.
Creation of the Activity object
The start of an Activity is a cross-process communication process. On the client side, the creation of an Activity is called back to the handleLaunchActivity() method in the ActivityThread:
frameworks/base/core/java/android/app/ActivityThread.java:
@Override
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {...finalActivity a = performLaunchActivity(r, customIntent); ...return a;
}
Copy the code
Then we find the creation of the Acitivity instance in the performLaunchActivity() method:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
···
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
// Note 1: Create a new Activity instance using the ClassLoader and the target Activity's class namejava.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ......}}Copy the code
The Activity related creation is left to the Instrumentation class:
frameworks/base/core/java/android/app/Instrumentation.java:
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);
}
Copy the code
The final creation is further handed over to the factory class AppComponentFactory:
frameworks/base/core/java/android/app/AppComponentFactory.java:
public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className, @Nullable Intent intent)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (Activity) cl.loadClass(className).newInstance();
}
Copy the code
At this point, the process of creating an Activity object is clear: we get the target Activity’s Class object from the ClassLoader object and its Class name, and then call the Class object’s newInstance() method to create an instance.
Graphically, it is shown as follows:
A reference to an Activity object
Now that you know how to create an Activity object, let’s go back to the original ActivityThread performLaunchActivity() method and move on:
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. The 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); ...// Note 2: The ActivityClientRecord object holds a reference to the Activity instance
r.activity = activity;
}
r.setState(ON_CREATE);
// Note 3: Add the ActivityClientRecord object to the mActivities collection
synchronized(mResourcesManager) { mActivities.put(r.token, r); }}...return activity;
}
Copy the code
Here we seem to have the answer:
The new Activity object will be passed inActivityClientRecordObject held, followed by theActivityClientRecordThe object will be added to a file namedmActivities
Is held in the collection of.
ActivityClientRecord is a static internal class of ActivityThread that records activity-related information. The object creation process can be found in the LaunchActivityItem class (after 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);
}
Copy the code
Take a look at the mActivities collection again:
frameworks/base/core/java/android/app/ActivityThread.java
:
...final ArrayMap<IBinder, ActivityClientRecord> mActivities = newArrayMap<>(); ...Copy the code
MActivities is a map collection that is a member variable of the ActivityThread object. Since it is a collection, you can also find the action to remove an element from the collection in the Activity destruction callback:
/** 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;
}
Copy the code
The graphical relationship is shown as follows:
Since an Activity object is indirectly referenced by an ActivityThread object, it should exist as a singleton. How is the singleton ActivityThread created and held?
Creation of the ActivityThread object
When a new application process is created, ActivityThread’s static main method main() is called. Here we find the answer:
frameworks/base/core/java/android/app/ActivityThread.java:
...// Note 4: Static ActivityThread member variables for singletons
private static volatileActivityThread sCurrentActivityThread; ...// Note 5: The main method entry for ActivityThread, called by RuntimeInit
public static void main(String[] args) {... stars. PrepareMainLooper (); ...// Note 6: Create a new ActivityThread object
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq); ... stars. The loop ();throw new RuntimeException("Main thread loop unexpectedly exited"); }...private void attach(boolean system, long startSeq) {
// Note 7: The ActivityThread object is referenced by static member variables
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) {
throwex.rethrowFromSystemServer(); } ···} ···}Copy the code
The sCurrentActivityThread is a static member of the ActivityThread class. When a new application process is created, create a new ActivityThread object in the main() method. This creates a relationship between an application process and an ActivityThread object (singleton).
conclusion
For every newly launched Activity, its object instance passes through the Class ClassnewInstance
Once created, the method is wrapped in an ActivityClientRecord object and added to the mActivitys member variable of the process’s unique ActivityThread object. In other words, Activity objects are held and released by ActivityThread.
Finally, I would like to reiterate two additional points:
- In the source code, the Activity object will have a transfer relationship in a number of methods, more complex, the author is unskilled, may miss some other important reference relationship did not analyze, welcome to point out.
- The above framework source code is the latest Version of Android Q before the deadline, different Versions of the Android system this part of the relevant source code will be changed, can not be compared and analyzed in detail, I hope you understand.
That’s all for this share. If you like it, you can like 👍 or follow it. Feel free to point out any mistakes in the comments.