Android window mechanism SDK31 source code analysis directory
- First acquaintance
- Creation and loading of DecorView and subdicor
- Creation and loading of Window and Window Manager
- The creation of ViewRootImpl and the real loading of the view
- Event distribution for ViewRootImpl
- Must be in the main thread to update the UI? Why?
- Relationship between Token and Dialog of Activity
- Toast mechanism
- summary
In the previous chapter, we learned about some column processes that occur after calling setContentView method. We can see that Window objects have been held in the Activity, so how are they related?
This chapter describes in detail.
First, several classes and interfaces are introduced
ViewManager
public interface ViewManager{ public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view); }
ViewManager is a set of interfaces that allow you to add and delete child views to an Activity.
For example, our common ViewGroup implements ViewManager, and the following WindowManager also inherits ViewManager.
WindowManager
//The interface that the application uses to talk to the window manager. Use context Getsystemservice (context. Window_service) gets one of them. public interface WindowManager extends ViewManager { //If the LayoutParams of addView is invalid, it will be thrown, or if the first View is not removed when adding a second View, it will be thrown public static class BadTokenException extends RuntimeException{...} //If a window is on a secondary display and the specified display cannot be found, it will be thrown public static class InvalidDisplayException extends RuntimeException{...} //Returns the Display managed by the current WindowManager public Display getDefaultDisplay(); //It means to remove the View from the Window. Generally, it is removed when the View calls onDetachedFromWindow, that is, after it is separated from the Window public void removeViewImmediate(View view); //Layout parameters of Window public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable{...} }
An interface that inherits the ViewManager, so you can add or delete views. The final implementation class is WindowManagerImpl.
In the first chapter, we analyzed that the implementation class of WindowManager is WindowManagerImpl, but all operations are delegated to WindowManagerGlobal within WindowManagerImpl. Here we repeat it to deepen our impression.
Source code analysis
OK, let's analyze the source code and see how Window, WindowManager and Activity are related.
For the source code of SDK31, the start of Activity will eventually call the execute(ClientTransaction transaction) method of TransactionExecutor, and then call the handleLaunchActivity, handleStartActivity and handleResumeActivity methods of ActivityThread in turn.
For this source code analysis, first omit other steps and directly view the source code in the handleLaunchActivity of ActivityThread.
ActivityThread public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) { ... //Initialize WindowManager service WindowManagerGlobal.initialize(); ... //Call performLaunchActivity final Activity a = performLaunchActivity(r, customIntent); ... return a; }
After initializing WindowManagerService, performLaunchActivity is called.
ActivityThread private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { //Create context with activity ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); //The Activity is instantiated through classLoader, and the support Activity object is created. activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); ... try { //Create / get Application Application app = r.packageInfo.makeApplication(false, mInstrumentation); //Judge whether to obtain the reserved window Window window = null; if (r.mPendingRemoveWindow != null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; r.mPendingRemoveWindow = null; r.mPendingRemoveWindowManager = null; } //Call the attach method of the activity 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, r.shareableActivityToken); ... //set up themes int theme = r.activityInfo.getThemeResource(); if (theme != 0) { activity.setTheme(theme); } ... //Callback onCreate of Activity. Through the analysis in the previous chapter, we know that DecorView is built here and held by Window. if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } //Set lifecycle state r.setState(ON_CREATE); ... return activity; }
The above comments are quite clear. Let's sort out what this method does. First, create the Context of the current Activity, build the Activity through ClassLoader, and then obtain the Application. Then, we pass in a series of parameters and call the attach method of the Activity, Finally, onCreate of Activity will be called and some related properties such as theme life cycle will be set.
So go to the attach method of Activity and see what you have done
Activity final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken, IBinder shareableActivityToken) { ... //Found, instantiate Window object mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(mWindowControllerCallback); //Set the CallBack callback. The CallBack obtained by getCallback at the end of the previous chapter is set at this time. mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); ... //Set UI Thread mUiThread = Thread.currentThread(); //Hold ActivityThread object mMainThread = aThread; ... //One key point is to set WindowManager for Window objects mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); if (mParent != null) { mWindow.setContainer(mParent.getWindow()); } //Hold the WindowManager object and obtain the WindowManager object through the getWindowManager of Window mWindowManager = mWindow.getWindowManager(); ... }
To be brief, in the attach ment of the Activity, the Window object is constructed and held by the Activity, so we can obtain the PhoneWindow through the getWindow method. After that, the WindowManager is passed into the Window, and the Activity will also hold the WindowManager object, and the WindowManager object can be obtained through getWindowManager.
In the performLaunchActivity method of ActivityThread, we can see that the onCreate method will not be called back until the call of attach is completed. Therefore, when we analyze the logic in the setContentView method of onCreate, we already include the Window object. Now that the handleLaunchActivity has been analyzed, let's take a look at handleStartActivity
ActivityThread public void handleStartActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, ActivityOptions activityOptions) { ... //Callback onStart method activity.performStart("handleStartActivity"); r.setState(ON_START); ... // Finally, the callback goes to onRestoreInstanceState(savedInstanceState) method if (pendingActions.shouldRestoreInstanceState()) { if (r.isPersistable()) { if (r.state != null || r.persistentState != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); } } else if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } ... }
When you see handleStartActivity, you call back the onStart method, and then call onRestoreInstanceState of the Activity to recover data.
Finally, let's look at the handleResumeActivity method.
ActivityThread public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) { ... //It will determine whether to call onRestart and onResume, and update the ActivityClientRecord data if (!performResumeActivity(r, finalStateRequest, reason)) { return; } ... //Window assignment if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; ... if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; //Bind DecorView and WindowManager through addView to prepare for view display wm.addView(decor, l); } } ... r.activity.mVisibleFromServer = true; mNumVisibleActivities++; if (r.activity.mVisibleFromClient) { //DecorView for display r.activity.makeVisible(); } ... } Activity //If mDecor is not added to WindowManager, add it again and display DecorView void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }
In handleResumeActivity, first call onRestart and onResume, then assign values to the data of window and decorview, and then bind and manage decorview through addView of WindowManager. Then display the decorview.
summary
Instantiate the activity in handleLaunchActivity, and then initialize WindowManager, Context, etc. window holds WindowManager and binds window object to the activity. Then call to setContentView in onCreate and create DecorView to be held by Window. At the same time, our own layout is included in decorview; After that, we call the handleStartActivity method, which calls onStart and onRestoreInstanceState. After calling handleResumeActivity, callback onResume is called, then DecorView is bound to WindowManager through WindowManager's addView method and WindowManager. Finally, makeVisible of Activity is displayed.
OK, so what exactly did the addView of WindowManager do? mDecor. How exactly is setvisibility displayed? See the next chapter for details: the creation of ViewRootImpl and the real loading of the view.
It's not easy to create. If you can help, you can use one key three times 🙆♀️. Welcome to technical discussion!