An article to get the "Drawing Process of View in Android"

Preface

Like the distribution of events, I also divide the drawing process of View into three parts
: 1. How to reach ViewRootImpl. 2. What did it do to reach ViewRootImpl. 3. The final drawing of View
After that, I will use an instance of custom View to ruminate this article, just like "An article is done and event distribution is done".

How to get to ViewRootImpl

The process is as follows:

1. First, the View is loaded in through the setContentView parsing xml in the onCreate stage of the Activity. That is, View is added to the cache during the OnCreate phase.
2. Which cache is it added to: This View object will be added to the ActivityClientRecord object of the ActivityThread (you can see it taken out and added to the DecorView later), and put into the mActivities collection of the ActivityThread to cache the status information of the current Activity object .
3. ActivityThread.handleResumeActivity() is called in the onResume phase of the Activity life cycle, and is used to set the Activity to the resumed state.
4. ActivityThread.handleResumeActivity() will call the addView() method of WindowManager to add the Window view of the Activity to the window. The source code is as follows:

@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
        boolean isForward, String reason) {
    
    
        .....
        final Activity a = r.activity;
        if (r.window == null && !a.mFinished && willBeVisible) {
    
    
            .....
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            if (!a.mWindowAdded) {
    
    
                ......
                a.mWindowAdded = true;
                wm.addView(decor, l);
            } else {
    
    
                a.onWindowAttributesChanged(l);
    }
}

5. You can see that in the ActivityThread.handleResumeActivity() method, the Window of the current Activity will be obtained first through the Activity's getWindow() method, and the relevant Window parameters will be set, and then the WindowManager's addView method will be called to add the Window's view to the window.
6. Here, ActivityClientRecord is just an information class of Activity, which records the status of Activity, the process it belongs to, and other related information.
7. The WindowManager implementation class is WindowManagerImpl, and the addView() method in WindowManagerImpl will call the addView() method of WindowManagerGlobal. The source code is as follows:

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
    
    
    ······
    root = new ViewRootImpl(view.getContext(), display);

    view.setLayoutParams(wparams);

    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);
    //即将开始流程绘制    
    root.setView(view, wparams, panelParentView);
    ·······
}

8. You can see that he will create the well-known ViewRootImpl. And give our View Set to ViewRootImpl for management.
The above process can be understood as the credit of Android Manager Service, which loads our View by managing the life cycle of Activity.

Flowchart summary:

insert image description here

What does it do to reach ViewRootImpl

Like the distribution of events, the final View is handed over to ViewRootImpl for management. This is why the ViewRootImpl code has tens of thousands of lines. After continuous iterations, the size of View has become very large. This may be the reason for the emergence of Jetpack Compose, to replace this huge View system, after all, it is difficult to maintain if it is huge.
Let's take a look at the key steps ViewRootImpl has made to draw the View.

Step 1: setView()

First of all, the setView of ViewRootImpl is mentioned above. What did setView do?
We know that the mView in ViewRootImpl is our root layout DecorView, which is also mentioned in the event distribution. Let’s say it again here:
In fact, the people who read the code carefully have already discovered it, in the first step of the handleResumeActivity method. We first created the window and got the decor, and set it to the next step through the wm.addView(decor, l) of windowsManager. Eventually it reaches ViewRootImpl.
Below is the setView method of ViewRootImpl.

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    
    
     if (mView == null) {
    
    
        mView = view;
         // Schedule the first layout -before- adding to the window
         // manager, to make sure we do the relayout before receiving
         // any other events from the system.
         requestLayout();
    }
}

You can see that ViewRootImpl first binds the view given by the window to its own mView. After all, you can only manage your own children, right?

Step 2: performTraversals()

The next step comes to the key method performTraversals() of View drawing.
As can be seen above, the requestLayout() method is executed, and the performTraversals() method is executed asynchronously in the requestLayout() method. The three major processes of View are all executed in this method.

@Override
public void requestLayout() {
    
    
    if (!mHandlingLayoutInLayoutRequest) {
    
    
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

At this point, we understand where the drawing process of View starts, and then analyze how this process is done.
Directly simplify the code of performTraversals for easy understanding (simplify ---- hee hee)

private void performTraversals() {
    
    

    //计算DecorView根View的MeasureSpecint childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

    performLayout(lp, mWidth, mHeight);

    performDraw();
}

The real mystery lies in performMeasure(), performLayout(), performDraw(), are you familiar with it? Did you think of it?
That's right, it seems that you have a good brain for learning Android. He finally called our mView, which is the three major drawing methods of DecorView.

Step 3: Measure(), Layout(), Draw() in DecorView

Let's take a look:
performMeasure()

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
    
    
    if (mView == null) {
    
    
        return;
    }
    try {
    
    
        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    } finally {
    
    
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

performLayout()

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
        int desiredWindowHeight) {
    
    
        final View host = mView;
        if (host == null) {
    
    
            return;
        }
        try {
    
    
            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
        } finally {
    
    
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }

The performDraw()
method does not directly call mView's Draw. It is to call the draw method first to call drawSoftware. In the end, Draw will still be called.
The source code is as follows: all simplified for easy understanding

private boolean performDraw() {
    
    
    try {
    
    
        boolean canUseAsync = draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);
        ....
    } finally {
    
    
        mIsDrawing = false;
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {
    
    
    if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
        scalingRequired, dirty, surfaceInsets)) {
    
    
    return false;
}

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
        boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
    
    
    try {
    
    
        ....
        mView.draw(canvas);
        ....
    } finally {
    
    
        mIsDrawing = false;
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}  

Finally, you can see that the Measure, Layout, and Draw methods of mView are called.
We clicked in and found that the Measure, Layout, and Draw of the View will call the well-known onMeasure(), onLayout(), and onDraw() methods. This source code will not be pasted out. You can click in and have a look.

View's final drawing

The so-called final drawing of View is. Simply put, the View is on the interface that is finally drawn through onMeasure(), onLayout(), and onDraw().
The following will analyze the knowledge of these three important methods, and then I will use two custom View articles to ruminate this knowledge point with examples.

First of all, we must know what is the View tree

onMeasure()

onLayout()

onDraw()

Guess you like

Origin blog.csdn.net/weixin_45112340/article/details/131306967