There were no clouds in the sky, where the fireballs glowed, forcing sweat through the pores.

I got out of my comfort zone and ran out for a few interviews.

The biggest feedback I get is that I don’t go far enough.

As an Android developer with five years of experience, there is still a lot to be desired.

preface

What is the process from the time a view instance is created to the time it is displayed on the screen? In Android development, this seems to be a basic knowledge, which should be clearly understood by developers, and it often appears as a question in interviews, but I still don’t understand it deeply. The drawing process of Android View is the core knowledge related to View. In this article, I hope to learn and share the basics of the Android View drawing process. And engrave it in your mind.

directory

This article is divided into the following process study, reading this article will learn PhoneWindow, WindowManger, ViewRootImpl, key links and role in the View. Understanding of window form mechanism and drawing process.

  1. Flow chart analysis
  2. Understand the view drawing process
  3. To understandsetContentViewHow to attach content to a page

Key class interpretation

  • Choreographer: Coordinates the timing of animation, input, and drawing.ChoreographerA timing pulse (such as vsync) is received from the display subsystem and work is arranged to occur as part of rendering the next display frame.

I. Flow chart analysis

1.1 Create an additional flowchart for an Activity window to setContentView

The following figure shows how the window was createdsetContentViewAfter the window view tree changes

1.2 View drawing flowchart

Ii. View drawing process

2.1 Analysis of drawing process

When we call requestLayout and invalidate, we’re going to ask the View to refresh the layout and draw. So starting with these two methods, you can complete the drawing process. Activities such as drawing animations are coordinated mainly through the Choreographer class.

  1. callrequestLayout andinvalidateMark drawing and filling layout information
  2. ChoreographerReceive system vSYNC and other pulse messages atscheduleTraversalsMethoddoTraversalStart traversing the View tree.
  3. The triggerViewRootImpl#performTraversalsThe view tree traversal is complete
    1. iflayoutRequestedIs true,measureHierarchyIn the measurementmViewAnd his sonview
    2. If necessary, triggerViewRootImpl#performLayoutTo complete the layout
    3. ifviewNot hidden andTreeObserverIf there is no interception drawing inperformDrawTo complete the drawing
      1. Calculates the dirty areas
      2. Get the dirty canvas from the mSurface and hand it to the View to draw

2.2 ViewRootImplCreate time

As you can see above, all drawings and layouts are triggered by viewrootimp #doTraversal, which then traverses the view tree it holds. So it’s important to understand when the ViewRootImpl and the DecorView it holds are created and associated. The key process is as follows:

  1. Activity#handleResumeIs calledWIndowManager#addViewadddecorView
  2. Calls to theWindowManagerGlobal#addViewWhen you createViewRootImplInstance.
  3. callViewRootImpl#setViewComplete a series of initialization methods
    1. registeredmDisplayListener toDisplayManagerTo receive the display update callback
    2. callrequestLayout Update the layout size and position letter once to ensure that the layout was done once before any other events were received from the system
    3. throughWindowSession Call addToDisplayAsUser, add window
  4. ScheduleTraversals is called to draw the View tree when a system event is received

WindowMangerGlobal ends up calling the ViewRootImpl method. The ViewRootImpl is initialized by calling the setView method after the addView DecorView, and receives the vSYNC pulse message as follows:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {... mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); .// 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(); .try{
                res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mDisplayCutout, inputChannel,
         
            } 
}
Copy the code

At the end of initialization, the window is added to the screen through the WindowSession call addToDisplayAsUser.

Attach contentView to interface

What happens when we launch an activity that displays the XML layout file we wrote on the screen? To present the content on the interface, there are several steps:

  1. Start the activity atperformLaunchActivityWhen you createActivityAttach and call the onCreate method
  2. At attach, create the PhoneWindow instance and hold the mWindow reference
  3. callsetContentViewTo attach content to Windows
  4. Through validationdecorView As well assubDecorViewExist, createDecorViewandsubDecorView
  5. addContentViewtodecorViewIn the treeR.id.contentnode
  6. whenhandleResumeActivityIs calledWindowManager.addView. associatedViewandViewRootImpl, then you can draw.

3.1 create PhoneWindow

Let’s first look at the method for launching an activity, ActivityThread#performLaunchAcivity. From the source code of this method, we can know that the method process of starting an activity is as follows:

  1. Create an Activity instance inInstrumentation#newActivitycomplete
  2. Create a PhoneWindows attachment to the Activity. inActivity#attachAcitivitycomplete
  3. To call an Activity’s onCreate lifecycle, the code isInstrumentation#callActivityOnCreate
  4. inonCreateTo execute user-defined code, such assetContentView.

So when the activity is ready to start, the PhoneWindows instance has been created. The next step is to execute the custom layout that we set by calling the setContentView method in Activity#onCreate.

3.2 The nature of setContentView

After an activity starts, we usually set our own layout file in the onCreate call setContentView. So let’s see exactly what setContentView does. The setContentView method essentially adds itself to android.R.ICtent. We see AppCompatDelegateImpl# the setContentView

@Override
public void setContentView(View v, ViewGroup.LayoutParams lp) {
    /// Confirm the window decorView and subDecorView
    ensureSubDecor();
    // Add contentView to android.R.ICtent
    ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
    contentParent.removeAllViews();
    contentParent.addView(v, lp);
    mAppCompatWindowCallback.getWrapped().onContentChanged();
}
Copy the code

The key to this piece of code is to add contentView to the child view whose ID is android.R.ICtent. The addView process naturally triggers a rerendering of the layout. The key is to create the decoView and subDecorView instantiation in the ensureSubDecor() method.

3.3 Confirm window, decorView, and subDecorView

First look at the main implementation of AppCompatDelegateImpl#ensureSubDecor() :

private void ensureSubDecor(a) {
    if (!mSubDecorInstalled) {
        mSubDecor = createSubDecor();
    }
}
private ViewGroup createSubDecor(a) {
    // Now let's make sure that the Window has installed its decor by retrieving it
    ensureWindow();
    mWindow.getDecorView();

    final LayoutInflater inflater = LayoutInflater.from(mContext);
    ViewGroup subDecor = null;

    // Omit the instantiation of other styles subDecor layouts
    ActionBar floatTitle ActionMode
   subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
  

    // Omit the status bar adaptation code
    // Omit the actionBar layout replacement code
    mWindow.setContentView(subDecor);
    return subDecor;
}
Copy the code

The code is long, with the main code above omitted. As you can see, the code logic is clear:

  • Step 1: Confirm window and attach(setting background and other operations)
  • Step 2: Get the DecorView, because it’s the first time it’s called, so the decor (create DecorView and Windows #ContentLyout)
  • Step 3: Instantiate the subDecor layout from THE XML
  • Step 4: Set the content layout:mWindow.setContentView(subDecor);

3.4 Initializing installDecor

The two key codes are Windows #installDecor and Windows #setContentView. Look at the code for Windows #installDecor:

private void installDecor(a) {
    mForceDecorInstall = false;
    mDecor = generateDecor(-1);
    if (mContentParent == null) {
        //R.id.content
        mContentParent = generateLayout(mDecor);
        final decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);

        if(decorContentParent ! =null) {
            / /... Omit some of the decorContentParent handling
        } else {
            mTitleView = findViewById(R.id.title);
            final View titleContainer = findViewById(R.id.title_container);
            /// Omit set mTitle to set the title container to show hidden
        }

        // Set the background
        // Omit the instantiation of the activity animation}}Copy the code

This one except for some titles. Beyond the initialization of the animation, the most important thing is

  • throughgenerateDecor()To generate theDecorView
  • And bygenerateLayout()To obtain theContentLayout
    • Obtain the windowStyle various attributes, and set the Features and the WindowManager. LayoutParams. Flags, etc
    • If window is a top-level container, obtain information such as background resources
    • Get various default layout instantiations (R.layout.screen_simple, etc.) and add them to the DecorView. andAppComptDelegateImpl#createSubDecorTo create thesubDecorSimilar.
    • To obtaincom.android.internal.R.id.contentLayout and return asContentLayout

Windows #setContentView:

@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    // decor, when theme attributes and the like are crystalized. Do not check the feature
    // before this happens.
    if (mContentParent == null) {
        installDecor();
    } else if(! hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); }if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        view.setLayoutParams(params);
        final Scene newScene = new Scene(mContentParent, view);
        transitionTo(newScene);
    } else {
        mContentParent.addView(view, params);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if(cb ! =null && !isDestroyed()) {
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}
Copy the code

The key code is simply to add a View to mContentParent. The mContentParent is the layout of andorid.R.D.C. Tent.

3.5 summary:

The analysis shows that the XML layout to display layout on the interface has gone through the following process:

  1. Start the activity

  2. Create PhoneWindow

  3. Set the layout setContentView

    1. Verify that subDecorView is initialized
      1. The initialization generates a DecorView
        1. Create DecorView in Window
        2. Create sample to code layout in Window as a child of DecorView (e.g. R.layout.smple)
        3. returncom.android.internal.R.id.contentAs ContentPrent
        4. In the Window handleDecorContentParent Layout, or handle things like headings
      2. Instantiate subDecorView, such as R.Layout.abc_screen_simple
      3. Set up thesubDecorViewTo the ContentPrent Window
    2. Add an instantiated Layout to android.R.id.content
  4. Call it addViewrequestLayout(); invalidate(true);

    1. requestLayoutTraverse the View tree to the DecorView, callingViewRootImpl#requestLayoutDuringLayout
    2. invalidateDetermine the views in the area and set the view that needs to be refreshed to dirty.
  5. Wait for the draw time (the handleResumeActivity will not trigger the draw) to passChoreographerTraverse the layout and draw operations of the View tree.

So we know exactly what happens when we setContentView. You’ve also seen how an activity can generate different layouts based on properties like float, title, and so on.

The last

This article describes the view drawing system in detail, but also the window mechanism and Android display mechanism of the pre-knowledge. View system is our UI development process in contact with the most Android knowledge. Understanding the art of painting is helpful for more than just interviews. For their own development work also has a lot of help.