preface

Recall the previous:Android custom View basics: An introduction to View wroot, DecorView & Window, it can be seen that the last step = draw

  • But before drawing, the system will have some preparation for drawing, namely the first few steps: createPhoneWindowClass,DecorViewClass,ViewRootmplClass etc.
  • Today, I will focus on the preparation of View drawing, mainly including: DecorView creation & display, hope you will enjoy.

1. Create a DecorView

A DecorView is the top-level View to display, so the preparation of the View begins with the creation of the DecorView.

Source code analysis

DecorView creation starts with the familiar setContentView().

/** * Activity setContentView() */ @override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Public void setContentView(int layoutResID) {// getWindow() function: Get the Activity member variable mWindow ->> Analyze 1 // Window class instance setContentView() ->> Analyze 2 getWindow().setContentView(layoutResID); initWindowDecorActionBar(); } /** * 1: mWindow */ / 1. Create a Window object (i.e. PhoneWindow instance) // Window class = abstract class, its only implementation class = PhoneWindow mWindow = new PhoneWindow(this, Window); / / 2. Set the callback, distribute click or to the Activity state change events such as mWindow. SetWindowControllerCallback (this); mWindow.setCallback(this); // 3. Set the WindowManager object mwindow.setwinDowManager ( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) ! = 0); } public void setContentView(int layoutResID) {// 1. If mContentParent is empty, DecorView = FrameLayout subclass if (mContentParent == null) {installDecor(); / / - > > analysis 3} else {/ / if not null, then delete the View mContentParent. RemoveAllViews (); } // 2. Add child View to mContentParent // that is, the layout file mLayOutInflater.inflate (layoutResID, mContentParent) set in the Activity; final Callback cb = getCallback(); if (cb ! = null && ! isDestroyed()) { cb.onContentChanged(); }} /** * Analysis 3: installDecor() * Function: Private void installDecor() {if (mDecor == null) {// 1. Generate DecorView ->> Analysis 4 mDecor = generateDecor(); mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); if (! mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures ! = 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); If (mContentParent == null) {mContentParent == null) {mContentParent = generateLayout(mDecor); . }}} /** * analysis 4: generateDecor() * GenerateDecor () {return new DecorView(getContext(), -1); } // Back to the original /** * analysis 5: generateLayout(mDecor) */ protected ViewGroup generateLayout(DecorView decor) {// 1. TypedArray a = getWindowStyle(); // 2. Load the window layout int layoutResource according to the theme style; int features = getLocalFeatures(); // 3. Load layoutResource View in = mLayOutInflater.inflate (layoutResource, null); // Add a child View to the DecorView // that is the layout mentioned in the DecorView introduction at the beginning of this article. That is just an example of loading different layouts depending on the theme style. decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); mContentRoot = (ViewGroup) in; DecorView = FrameLayout subclass ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); return contentParent; }Copy the code

Source summary

  1. Create an instance object of PhoneWindow, a subclass of the Window abstract class.
  2. Set the WindowManager object for the PhoneWindow class object;
  3. Create a DecroView class object for the PhoneWindow class object (added according to the theme style of your choice);
  4. Add the layout file set in the Activity to the Content in the DecroView class object.

At this point, the DecorView(that is, the top-level View) has been created and added to the layout file set up in the Activity, but is not currently displayed, that is, not visible.


2. Display of DecorView

Source code analysis

When the main thread is created, handleResumeActivity() is called and the display of the DecorView begins.

/** ** When the main thread is created, Call handleResumeActivity() */ @override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } /** * SetContentView () */ Final void handleResumeActivity(IBinder Token, Boolean clearHide, Boolean isForward, boolean reallyResume) { ActivityClientRecord r = performResumeActivity(token, clearHide); if (r ! = null) { final Activity a = r.activity; if (r.window == null && ! a.mFinished && willBeVisible) { // 1. Get the Decor object r.window = R.activity. GetWindow () in the Window instance; View decor = r.window.getDecorView(); // 2. Decor. SetVisibility (view.invisible); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; If (a.visibleFromClient) {a.windowAdded = true; wm.addView(decor, l); } // 4. Set DecorView to visible if (! r.activity.mFinished && willBeVisible && r.activity.mDecor ! = null && ! r.hideForNow) { if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); // -- >> Analyze 1}}} /** * analyze 1: activity.makevisible () */ void makeVisible() {if (! mWindowAdded) { ViewManager wm = getWindowManager(); // 1. Add DecorView to WindowManager ->> Analysis 2 Wm.addView (mDecor, getWindow().getAttributes()); mWindowAdded = true; } // 2. DecorView mDecor. SetVisibility (view.visibility); } /** * analysis 2: wm.addView * function: WindowManager = 1 interface, Implements WindowManagerImpl */ Public Final Class WindowManagerImpl implements WindowManager {private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); @Override public void addView(View view, ViewGroup.LayoutParams params) { mGlobal.addView(view, params, mDisplay, mParentWindow); ->> Analysis 3}} /** * Analysis 3: WindowManagerGlobal addView() */ public void addView(View View, viewgroup.layoutParams,Display Display, Window parentWindow) { final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; . Synchronized (mLock) {// 1. Instantiate a ViewRootImpl object ViewRootImpl root; root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); } // 2. WindowManager passes the DecorView instance object to ViewRootImpl to draw the View root.setView(View, wParams, panelParentView); // ->> analysis 4}}} /** * analysis 4: ViewRootImpl. SetView () * / public void setView (View View, WindowManager. LayoutParams attrs. View panelParentView) { requestLayout(); / / - > > 5, 5} / * * * analyses ViewRootImpl. RequestLayout () * / @ Override public void requestLayout () {if (! mHandlingLayoutInLayoutRequest) { // 1. Check whether the main thread is checkThread(); mLayoutRequested = true; //mLayoutRequested whether to measure and layout the information panel. // 2. ->> analyse 6 scheduleTraversals(); 6:}} / * * * analysis ViewRootImpl. ScheduleTraversals () * / void scheduleTraversals () {if (! mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); // Send a runnable via mhandler.post (), Draw the process in the run() method // similar to ActivityThread's Handler messaging mechanism // ->> Analysis 7 mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); }} /* traversalRunnable class traversalRunnable */ Final class TraversalRunnable implements Runnable {@override public void run() {doTraversal(); }} final TraversalRunnable() = new TraversalRunnable(); Traversal() {mhandler.getLooper ().getQueue().removesyncbarrier (mTraversalBarrier); performTraversals(); // performTraversals() will be called to start the View's 3 traversals: Measure, Layout, Draw} Class W is a Native end of Binder, which is used to receive WmS processing operations. Because the receiving method of class W is in the thread pool, event processing can be switched to the main thread through a HandlerCopy the code

Source summary

  1. Add a DecorView object to the WindowManager;
  2. Create the ViewRootImpl object;
  3. WindowManager passes the DecorView object to the ViewRootImpl object;
  4. The ViewRootImpl object sends a message to the main thread via Handler to trigger traversals: performTraversals(); This method is used to execute the View’s drawing process (measure, layout, draw).

The various changes received in the ViewRootImpl object (such as window property changes from the WmS, size changes from the control tree, redraw requests, etc.) cause performTraversals() to be called and processed, and eventually shown in the visible Activity. The whole process is shown below.

It can be seen from the above conclusion that:

  • Each performTraversals() call drives the tree to work methodically;
  • If this method fails to execute properly, the entire control tree is in a dead state;
  • PerformTraversals () is therefore the core logic of the ViewRootImpl class object. The subsequent logic of performTraversals() is the three main processes of View rendering: measure, layout and draw.

3. Summary

  • This article provides a comprehensive overview of customizationsViewPreparation before drawing mainly includes:DecorViewCreate & display, summarized as follows:
  • Workflow mechanism

  • Source code analysis

For more on Android custom Views, stay tuned: Carson takes you to Android


Welcome to attentionCarson takes you through Android blogs

Blog link: juejin.cn/user/252413…


Please give the top/comment a thumbs up! Because your encouragement is the biggest power that I write!