Personal blog address http://dandanlove.com/

preface

I’ve written two articles about views recently: Window setContentView and Meeting LayoutInflater&Factory. Analysis of the Activity to set the page layout to the page View elements layout in the end experienced a what process?

  • The PhoneWindow object is generated in attach of the Activity;
  • Initialize DecorView (ViewGroup) in setContentView;
  • More parsed data after LayoutInflater parses layout files
  • According to the parsed data to execute the View constructor to construct the View, and generate the ViewTree.

Why continue to write this article? Because I saw a child thread update View in the nuggets after the article, found himself on the View is not very, to this problem as the direction of the View related source code. I found some articles on the network for the analysis of ViewRootImpl or some problems or doubts, so I sorted out the knowledge points to share with you, I hope to be helpful to you. (source code CM12.1)

The View of the introduction

When I first learned View, I first analyzed its layout (LinearLayout, FrameLayout, TableLayout, RelativeLayout, AbsoluteLayout) and then its three methods (measure, layout, draw) ).

View—–onMeasure()

  • MeasureSpec.EXACTLY is the exact size when we specify layout_width or layout_height as a specific value like andorID :layout_width=”50dip” or FILL_PARENT Both are cases where the size of the control has been determined, and both are exact sizes.
  • MeasureSpec.AT_MOST is the maximum size. When a control’s layout_width or layout_height is specified as WRAP_CONTENT, the control size generally varies with the control’s subspace or content, as long as the control size does not exceed the maximum size allowed by the parent control. Therefore, mode is AT_MOST, and size gives the maximum size allowed by the parent control.
  • UNSPECIFIED. The parent control is an AdapterView, and the mode is passed in via the Measure method.

ViewGroup.java

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec)
protected void measureChild(View child, int parentWidthMeasureSpec,int parentHeightMeasureSpec)
protected void measureChildWithMargins(View child,int parentWidthMeasureSpec, int widthUsed,int parentHeightMeasureSpec, int heightUsed)
Copy the code

Draw & Load View—–onLayout()

  • OnLayout method: is the layout method of the subview of the ViewGroup. Placing a child View is very simple, just rewrite the onLayout method, and then get the child View instance, call the child View layout method to achieve the layout. In practical development, onMeasure measurement method is generally used together. Views are placed according to a rectangular space.
  • Layout method: is the View placement method, in the View class implementation. Calling this method requires passing in the values left and top in the upper left corner and right and bottom in the lower right corner of the rectangular space where the View is placed.

Draw & load View—–onDraw()

public void draw(Canvas canvas)
protected void onDraw(Canvas canvas)
protected void dispatchDraw(Canvas canvas)(View,ViewGroup)
protected boolean drawChild(Canvas canvas, View child, long drawingTime) (ViewGroup)
Copy the code


ViewTree.jpg

View parsing and generation

View parsing and generation are covered in the following two articles

How the View is presented on the page, how the View tree is generated. The setContentView of the Window in the Activity

View object generation, initialization of property values. Meet LayoutInflater&Factory

I’ve used some of the relevant Android classes in these two articles:

  • Activity: An Activity is an application component that provides a screen that users can interact with to complete a task, such as dialing, taking a photo, sending an email… .
  • View: As the base class for all graphics.
  • ViewGroup: Extends View inheritance to a View container class.
  • Window: It Outlines the basic properties and functions of Android Windows. (Abstract class)
  • PhoneWindow: a subclass of Window.
  • DecorView: The root View of the interface, the inner class of PhoneWindow.
  • ViewRoot PL :ViewRoot is a bridge between GUI management systems and GUI rendering systems.
  • WindowManangerService: Short for WMS, it is used to manage Windows in all applications and to manage the various user interactions with these Windows.

ViewRootImpl profile

The top of a view hierarchy, implementing the needed protocol between View and the WindowManager. This is for the most part an internal implementation detail of {@link WindowManagerGlobal}.

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer. HardwareDrawCallbacks {/ * * * * * * * part of the code omitted * * * * * * * * * * /}Copy the code

ViewRootImpl is the highest level in the View, the root of all views (ViewRootImpl is not a View, but implements the ViewParent interface), and implements the communication protocol between the View and WindowManager. The implementation details are in the Windows ManagerGlobal class.


ViewManager.png

Public void addView(View View, viewGroup.layoutParams params); View public void updateViewLayout(View View, viewGroup.layoutParams params); Public void removeView(View View); }Copy the code

WindowManager adds, updates, and deletes views, but what about Windows in between?

Reading this article, we know that there is a Window object in an Activity. A Window object corresponds to a DecorView, and the ViewRootImpl operates on that View.

We know that all elements of the interface are made up of Views, and every pixel on the interface is drawn by views. Window is an abstract concept that abstracts an interface as a Window object, or as a View.

Relationships between ViewRootImpl and other classes

Before we look at how ViewRootImpl relates to other classes, let’s look at a diagram and some code:


ViewRootImpl.jpg

Public Final class WindowManagerGlobal {/******* ********** private Final ArrayList<View> mViews = new ArrayList<View>(); Private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); / / all Window object corresponding to the View of the private final layout parameters ArrayList < WindowManager. LayoutParams > mParams = new ArrayList<WindowManager.LayoutParams>(); /******* **********/}Copy the code
  • Windows ManagerGlobal stores the mapping between View View PL and View instances internally (sequentially).

  • WindowManager inherit with ViewManger, from ViewManager this class name is used to View class management, from ViewManager interface add, update, delete View method can also be seen WindowManager View management.

public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mDisplay, mParentWindow); } @Override public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.updateViewLayout(view, params); } @Override public void removeView(View view) { mGlobal.removeView(view, false); } /******* **********/}Copy the code
  • WindowManagerImplforWindowManagerImplementation class of.WindowManagerImplInternal method implementations are made by proxy classesWindowManagerGlobalFinish the,WindowManagerGlobalIs a singleton, that is, there is only one in a processWindowManagerGlobalObject serves the View of all pages.

Initialization of ViewRootImpl

After the Activity’s onResume, the View from the current Activity’s Window object is added to the WindowManager.

Public final class ActivityThread {/******* **********/ final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, Boolean reallyResume) {/******* **********/ // TODO Push resumeArgs into the activity for consideration ActivityClientRecord r = performResumeActivity(token, clearHide); if (r ! = null) {/ * * * * * * * part of the code omitted * * * * * * * * * * / if (truly indow = = 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; // Window type: an application window type (all application window types are displayed at the top). l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { a.mWindowAdded = true; // Add decor to WindowManager wm. AddView (decor, l); } // If the window has already been added, but during resume // we started another activity, then don't yet make the // window visible. } else if (! willBeVisible) { if (localLOGV) Slog.v( TAG, "Launch " + r + " mStartedActivity set"); r.hideForNow = true; } /******* **********/} else {// If an exception was thrown when trying to resume, then // just end this activity. try { ActivityManagerNative.getDefault() .finishActivity(token, Activity.RESULT_CANCELED, null, false); } catch (RemoteException ex) { } } } }Copy the code

Create the ViewRootImpl for the Window and add the View, ViewRootImpl, and LayoutParams for the Window to the WindowManager in sequence.

Public final class WindowManagerGlobal {/******* **********/ public void addView(View View, ViewGroup.LayoutParams params, Display display, Window parentWindow) {if (view == null) {throw new IllegalArgumentException("view must not be null"); } if (display == null) { throw new IllegalArgumentException("display must not be null"); } if (! (params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; if (parentWindow ! = null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } else { // If there's no parent and we're running on L or above (or in the // system context), assume we want hardware acceleration. final Context context = view.getContext(); if (context ! = null && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; }} // declare ViwRootImpl ViewRootImpl root; View panelParentView = null; synchronized (mLock) { // Start watching for system property changes. if (mSystemPropertyUpdater == null) { mSystemPropertyUpdater = new Runnable() { @Override public void run() { synchronized (mLock) { for (int i = mRoots.size() - 1; i >= 0; --i) { mRoots.get(i).loadSystemProperties(); }}}}; SystemProperties.addChangeCallback(mSystemPropertyUpdater); } int index = findViewLocked(view, false); if (index >= 0) { if (mDyingViews.contains(view)) { // Don't wait for MSG_DIE to make it's way through root's queue. mRoots.get(index).doDie(); } else { throw new IllegalStateException("View " + view + " has already been added to the window manager."); } // The previous removeView() had not completed executing. Now it has. } // If this is a panel window, then find the window it is being // attached to for future reference. if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { final int count = mViews.size(); for (int i = 0; i < count; i++) { if (mRoots.get(i).mWindow.asBinder() == wparams.token) { panelParentView = mViews.get(i); }} // create ViwRootImpl root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); // Add mviews.add (View); mRoots.add(root); mParams.add(wparams); } // do this last because it fires off messages to start doing things try {// set the View of Window to create ViewRootImpl // Update the interface via ViewRootImpl and complete the Window addition process. root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. synchronized (mLock) { final int index = findViewLocked(view, false); if (index >= 0) { removeViewLocked(index, true); } } throw e; }}}Copy the code

The ViewRootImpl binds the View corresponding to the Window

The ViewRootImpl binds the View corresponding to the Window, and measures, layouts, and draws the View.

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer. HardwareDrawCallbacks {/ * * * * * * * part of the code omitted * * * * * * * * * * * * * / / We have one child * / public void setView (View) view, WindowManager.LayoutParams attrs, View panelParentView) {synchronized (this) {if (mView == null) {//ViewRootImpl member variable View to copy, later operation is mView. mView = view; / * * * * * * * part of the code omitted * * * * * * * * * * / / / the Window before adding a layout, make sure to accept system again after other events to layout. // Asynchronously refresh the View and execute the View drawing method. requestLayout(); if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { mInputChannel = new InputChannel(); } try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); // Add the Window to the screen. //mWindowSession implements the IWindowSession interface, which is the client object of the Session Binder. Inform WindowManagerService add IWindow res = mWindowSession. AddToDisplay (mWindow mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel); } catch (RemoteException e) { mAdded = false; mView = null; mAttachInfo.mRootView = null; mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocus(null, null); throw new RuntimeException("Adding window failed", e); } finally { if (restore) { attrs.restore(); * * * * * * *}} / part of the code omitted * * * * * * * * * * / / / set the current View of mParent the assignParent (this); /******* / **********/}}}}Copy the code

The ViewRootImpl operates on the mView

The operations on the View include measurement, layout, and rendering as described at the beginning of this article, mainly in View otimpl’s performTraversals method.

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer. HardwareDrawCallbacks {/ * * * * * * * part of the code omitted * * * * * * * * * * / / / request for interface layout @ Override public void requestLayout () { if (! mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); }} mThread = thread.currentThread ();}} mThread = thread.currentThread (); void checkThread() { if (mThread ! = Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); }} void scheduleTraversals() {if (! mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (! mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); } } final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); }} void doTraversal() {if (mTraversalScheduled) {mTraversalScheduled = false; mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); if (mProfile) { Debug.startMethodTracing("ViewAncestor"); } Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals"); // Execute task performTraversals(); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } if (mProfile) { Debug.stopMethodTracing(); mProfile = false; }}} private void performTraversals() {// Cache mView since it is used so much below... final View host = mView; / * * * * * * * part of the code omitted * * * * * * * * * * / / / want to show the width of the window high int desiredWindowWidth; int desiredWindowHeight; / / layout to prepare the if (mFirst | | windowShouldResize | | insetsChanged | | viewVisibilityChanged | | params! = null) {/******* **********/ if (! mStopped) { boolean focusChangedDueToTouchMode = ensureTouchModeLocally( (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) ! = 0); if (focusChangedDueToTouchMode || mWidth ! = host.getMeasuredWidth() || mHeight ! = host.getMeasuredHeight() || contentInsetsChanged) { int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); // Ask host how big it wants to be performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); // Implementation of weights from WindowManager.LayoutParams // We just grow the dimensions as needed and re-measure if // needs be int width = host.getMeasuredWidth(); int height = host.getMeasuredHeight(); boolean measureAgain = false; /******* **********/ if (measureAgain) {//View's measure performMeasure(childWidthMeasureSpec, childchildMeasurespec); } layoutRequested = true; }}} else {/ * * * * * * * part of the code omitted * * * * * * * * * * /} final Boolean didLayout = layoutRequested / * &&! mStopped*/ ; boolean triggerGlobalLayoutListener = didLayout || mAttachInfo.mRecomputeGlobalAttributes; If (didLayout) {//View performLayout(LP, desiredWindowWidth, desiredWindowHeight); / * * * * * * * part of the code omitted * * * * * * * * * * /} / * * * * * * * part of the code omitted * * * * * * * * * * / if (! cancelDraw && ! newSurface) { if (! SkipDraw | | mReportNextDraw) {/ * * * * * * * part of the code omitted * * * * * * * * * * / / / the View of drawing performDraw (); } } else { if (viewVisibility == View.VISIBLE) { // Try again scheduleTraversals(); } else if (mPendingTransitions ! = null && mPendingTransitions.size() > 0) { for (int i = 0; i < mPendingTransitions.size(); ++i) { mPendingTransitions.get(i).endChangingAnimations(); } mPendingTransitions.clear(); } } mIsInTraversal = false; }}Copy the code

The View of measurement

The ViewRootImpl calls performMeasure to measure the View corresponding to the Window.

  • ViewRootImplçš„performMeasure;
  • DecorView (FrameLayout) measure;
  • DecorView onMeasure (FrameLayout);
  • DecorView(FrameLayout) Measure of all child views;
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer. HardwareDrawCallbacks {/ * * * * * * * part of the code omitted * * * * * * * * * * / / / the View of measurement of private void performMeasure (int childWidthMeasureSpec, int childHeightMeasureSpec) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure"); DecorView (FrameLayout) mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); }}}Copy the code

The layout of the View

ViewRootImpl calls performLayout to perform the layout of the View corresponding to the Window.

  • ViewRootImpl performLayout;
  • DecorView(FrameLayout) layout method;
  • DecorView(FrameLayout) onLayout method;
  • DecorView(FrameLayout) layoutChildren method
  • DecorView(FrameLayout);

During this time it is possible that the View itself will touch the publish layout request, so requestLayout of ViewRootImpl will be called here during this process to remeasure, rearrange, and redraw.

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer. HardwareDrawCallbacks {/ * * * * * * * part of the code omitted * * * * * * * * * * / / / request to layout the ViewRootImpl @ Override public void requestLayout() { if (! mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); }} / / the View layout private void performLayout (WindowManager. LayoutParams lp, int desiredWindowWidth, Int desiredWindowHeight) {/******* **********/ final View host = mView; / * * * * * * * part of the code omitted * * * * * * * * * * / try {/ / call the View Layout method of Layout host. The Layout (0, 0, host getMeasuredWidth (), host.getMeasuredHeight()); mInLayout = false; // During the ViewRootImpl layout, the View in the Window itself performs requestLayout int numViewsRequestingLayout = mLayoutRequesters. Size (); if (numViewsRequestingLayout > 0) { // requestLayout() was called during layout. // If no layout-request flags are set on the requesting views, there is no problem. // If some requests are still pending, then we need to clear those flags and do // a full request/measure/layout pass to handle this situation. ArrayList<View>  validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, false); if (validLayoutRequesters ! = null) { // Set this flag to indicate that any further requests are happening during // the second pass, which may result in posting those requests to the next // frame instead mHandlingLayoutInLayoutRequest = true; // Process fresh layout requests, then measure and layout int numValidRequests = validLayoutRequesters.size(); for (int i = 0; i < numValidRequests; ++i) { final View view = validLayoutRequesters.get(i); Log.w("View", "requestLayout() improperly called by " + view + " during layout: running second layout pass"); Request View.requestLayout (); request view.requestLayout(); request View.requestLayout (); } measureHierarchy(host, lp, mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight); mInLayout = true; host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); mHandlingLayoutInLayoutRequest = false; // Check the valid requests again, this time without checking/clearing the // layout flags, since requests happening during the second pass get noop'd validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true); if (validLayoutRequesters ! = null) { final ArrayList<View> finalRequesters = validLayoutRequesters; // Post second-pass requests to the next frame getRunQueue().post(new Runnable() { @Override public void run() { int numValidRequests = finalRequesters.size(); for (int i = 0; i < numValidRequests; ++i) { final View view = finalRequesters.get(i); RequestLayout (); requestLayout(); requestLayout(); }}}); } } } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } mInLayout = false; }}Copy the code

The View of the drawing

ViewRootImpl calls performDraw to perform the layout of the View corresponding to the Window.

  • ViewRootImpl performDraw;
  • The draw ViewRootImpl;
  • ViewRootImpl drawSoftware;
  • DecorView(FrameLayout) draw method;
  • DecorView(FrameLayout) dispatchDraw method;
  • DecorView(FrameLayout) drawChild method;
  • DecorView(FrameLayout) draw method for all child views
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer. HardwareDrawCallbacks {/ * * * * * * * part of the code omitted * * * * * * * * * * / / / the View of drawing private void performDraw () {if (mAttachInfo.mDisplayState == Display.STATE_OFF && ! mReportNextDraw) { return; } final boolean fullRedrawNeeded = mFullRedrawNeeded; mFullRedrawNeeded = false; mIsDrawing = true; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); try { draw(fullRedrawNeeded); } finally { mIsDrawing = false; Trace.traceEnd(Trace.TRACE_TAG_VIEW); * * * * * * *} / part of the code omitted * * * * * * * * * * /} / / to draw private void the draw (Boolean fullRedrawNeeded) {/ * * * * * * * part of the code omitted * * * * * * * * * * / / / the View on the Observer of drawing events distribution mAttachInfo. MTreeObserver. DispatchOnDraw (); if (! dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) { if (mAttachInfo.mHardwareRenderer ! = null && mAttachInfo. MHardwareRenderer. IsEnabled ()) {/ * * * * * * * part of the code omitted * * * * * * * * * * / / / call Window corresponding ViewRootImpl invalidate method mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this); } else {/ * * * * * * * part of the code omitted * * * * * * * * * * / / / draw the Window if (! drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) { return; } } } if (animating) { mFullRedrawNeeded = true; scheduleTraversals(); } } void invalidate() { mDirty.set(0, 0, mWidth, mHeight); if (! mWillDrawSoon) { scheduleTraversals(); } } /** * @return true if drawing was successful, false if an error occurred */ private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, The Rect dirty) {/ * * * * * * * part of the code omitted * * * * * * * * * * / try {/ * * * * * * * part of the code omitted * * * * * * * * * * / try {canvas. Translate (xoff, -- yoff); if (mTranslator ! = null) { mTranslator.translateCanvas(canvas); } canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0); attachInfo.mSetIgnoreDirtyState = false; / / the View rendering mView. The draw (canvas); drawAccessibilityFocusedDrawableIfNeeded(canvas); } finally { if (! attachInfo.mSetIgnoreDirtyState) { // Only clear the flag if it was not set during the mView.draw() call attachInfo.mIgnoreDirtyState = false; The finally}}} {/ * * * * * * * part of the code omitted * * * * * * * * * * /} return true; }}Copy the code

The asynchronous thread updates the view

Can views be updated in asynchronous threads at all? Let’s start by looking at the code execution flowchart for textView.settext.


setText.png

Check whether the current thread is the same thread on which the ViewRootImpl was created. The ViewRootImpl is created after the Activity’s onResume life cycle.

  • We can go back toonResumePreviously, the view update was done on an asynchronous thread because no thread validation would occur at this time.
  • We can initialize the asynchronous thread againViewRootImplView updates are made on this thread at the same time.

PS: We study the Android source code and by understanding its internal implementation, we can remove, add, or modify some of the code logic by technical means. In order to expect to make better products, do more detailed optimization. But we still have to follow the rule that this interface can only be drawn on the main thread. Two threads cannot draw at the same time, otherwise the screen will be drawn. Do not write to the same memory at the same time, otherwise the memory will be exhausted. Do not write the same document at the same time, otherwise the document will be wasted. Only one thread can do UI at a time, so when the odds of two threads being mutually exclusive are high, or when the code guaranteeing mutual exclusion is complex, choosing one of them to hold the other messages for a long time is a typical solution. So the general requirement is that the UI be single-threaded.

Different viewrotimpl for Activity, Dialog, Toast

The previous sections of this article have been parsing the code from the perspective of an Activity, so instead of analyzing Dialog and Toast and activities, we will focus on how they differ from activities. See Dialog, Toast’s Window, and ViewRootImpl for details.

conclusion

With a more detailed look at View View PL, it becomes clearer to look at some of the ways in which you can customize the layout of a View. It also solves the puzzle of the asynchronous thread updating View in Android.

The article here is all about the end, if there are other need to communicate can leave a message!!

To read more articles by the author, check out my personal blog and public account:


The revitalization of book city