[learning] the working principle of View in Android -- ViewRoot, DecorView and MeasureSpec

Get to know ViewRoot and DecorView

ViewRoot corresponds to the ViewRootImpl class. It is the link between WindowManager and DecorView. The three major processes of View are completed through ViewRoot. In the ActivityThread, after the Activity is created, the DecorView will be added to the Window, the ViewRootImpl object will be created, and the ViewRootImpl object will be associated with the DecorView.

The drawing process of View starts from the performTraversals method of ViewRoot. It can finally draw a View through three processes: measure, layout and draw. Measure is used to measure the width and height of the View, layout is used to determine the position of the View in the parent container, and draw is responsible for drawing the View on the screen.
In the above figure, performTraversals will call performMeasure, performLayout, and performDraw in turn. These three methods complete the measure, layout, and draw processes of the top-level View respectively. In performMeasure, the measure method will be called, and in measure, the onMeasure method will be called. In onMeasure, the measure process will be performed on all child elements. At this time, the measure process will be transferred from the parent container to the child elements, thus completing a measure process. Next, the child element will repeat the measure process of the parent container, thus completing the traversal of the entire View. Similarly, the layout and draw processes are similar to them. The only difference is that the transfer process of performDraw is implemented through dispatchDraw in the draw method.

The measure process determines the width and height of the View. After the measure is completed, the measured width and height of the View can be obtained through the getMeasuredWidth and getMeasureHeight methods. In almost all cases, it is equal to the final width and height of the View.

The layout process determines the coordinates of the four vertices of the View and the width and height of the actual View. After completion, you can get the positions of the four vertices of the View through getTop, getbottom, getleft and getright, and get the final width and height of the View through getWidth and getHeight.

The draw process determines the display of the View. Only after the draw method is completed can the content of the View be displayed on the screen.


As shown in the above figure, DecorView, as a top-level View, generally contains a vertical LinearLayout. In this LinearLayout, there are two parts (related to the Android version and theme), the title bar above and the content below. In Activity, the layout file we set through setContentView is actually added to the content bar, and the id of the content bar is content. Therefore, it can be understood that the method for Activity to specify the layout is not setview but setContentView, because our layout is indeed added to the FrameLayout with id of content.

How to get content?

ViewGroup content=findViewById(R.android.id.content)

How do we get the View we set?

content.getChildAt(0) Through the source code, we can find that the DecorView is a FrameLayout, and the events of the View layer first pass through the DecorView and then pass to our View.

MeasureSpec

MeasureSpec largely determines the dimension of a View. The reason is that this process is also affected by the parent container, because the parent container affects the creation process of the MeasureSpec of the View. During the measurement, the system will convert the LayoutParams of the View into the corresponding MeasureSpec according to the rules imposed by the parent container, and then measure the width and height of the View according to the MeasureSpec. The width and height here refers to the measured width and height, which is not necessarily equal to the final width and height of the View.

MeasureSpec represents a 32-bit int value, the upper 2 bits represent SpecMode, and the lower 30 bits represent SpecSize. SpecMode refers to the measurement mode, and SpecSize refers to the specification size in a certain measurement mode.

 * A MeasureSpec encapsulates the layout requirements passed from parent to child.
 * Each MeasureSpec represents a requirement for either the width or the height.
 * A MeasureSpec is comprised of a size and a mode. There are three possible
 * modes:
 * <dl>
 * <dt>UNSPECIFIED</dt>
 * <dd>
 * The parent has not imposed any constraint on the child. It can be whatever size
 * it wants.
 * </dd>
 *
 * <dt>EXACTLY</dt>
 * <dd>
 * The parent has determined an exact size for the child. The child is going to be
 * given those bounds regardless of how big it wants to be.
 * </dd>
 *
 * <dt>AT_MOST</dt>
 * <dd>
 * The child can be as large as it wants up to the specified size.
 * </dd>
 * </dl>
 *
 * MeasureSpecs are implemented as ints to reduce object allocation. This class
 * is provided to pack and unpack the &lt;size, mode&gt; tuple into the int.
 */
public static class MeasureSpec {
    private static final int MODE_SHIFT = 30;
    private static final int MODE_MASK  = 0x3 << MODE_SHIFT;

    /** @hide */
    @IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
    @Retention(RetentionPolicy.SOURCE)
    public @interface MeasureSpecMode {}

    /**
     * Measure specification mode: The parent has not imposed any constraint
     * on the child. It can be whatever size it wants.
     */
    public static final int UNSPECIFIED = 0 << MODE_SHIFT;

    /**
     * Measure specification mode: The parent has determined an exact size
     * for the child. The child is going to be given those bounds regardless
     * of how big it wants to be.
     */
    public static final int EXACTLY     = 1 << MODE_SHIFT;

    /**
     * Measure specification mode: The child can be as large as it wants up
     * to the specified size.
     */
    public static final int AT_MOST     = 2 << MODE_SHIFT;

    /**
     * Creates a measure specification based on the supplied size and mode.
     *
     * The mode must always be one of the following:
     * <ul>
     *  <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li>
     *  <li>{@link android.view.View.MeasureSpec#EXACTLY}</li>
     *  <li>{@link android.view.View.MeasureSpec#AT_MOST}</li>
     * </ul>
     *
     * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's
     * implementation was such that the order of arguments did not matter
     * and overflow in either value could impact the resulting MeasureSpec.
     * {@link android.widget.RelativeLayout} was affected by this bug.
     * Apps targeting API levels greater than 17 will get the fixed, more strict
     * behavior.</p>
     *
     * @param size the size of the measure specification
     * @param mode the mode of the measure specification
     * @return the measure specification based on size and mode
     */
    public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
                                      @MeasureSpecMode int mode) {
        if (sUseBrokenMakeMeasureSpec) {
            return size + mode;
        } else {
            return (size & ~MODE_MASK) | (mode & MODE_MASK);
        }
    }

    /**
     * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED
     * will automatically get a size of 0. Older apps expect this.
     *
     * @hide internal use only for compatibility with system widgets and older apps
     */
    @UnsupportedAppUsage
    public static int makeSafeMeasureSpec(int size, int mode) {
        if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
            return 0;
        }
        return makeMeasureSpec(size, mode);
    }

    /**
     * Extracts the mode from the supplied measure specification.
     *
     * @param measureSpec the measure specification to extract the mode from
     * @return {@link android.view.View.MeasureSpec#UNSPECIFIED},
     *         {@link android.view.View.MeasureSpec#AT_MOST} or
     *         {@link android.view.View.MeasureSpec#EXACTLY}
     */
    @MeasureSpecMode
    public static int getMode(int measureSpec) {
        //noinspection ResourceType
        return (measureSpec & MODE_MASK);
    }

    /**
     * Extracts the size from the supplied measure specification.
     *
     * @param measureSpec the measure specification to extract the size from
     * @return the size in pixels defined in the supplied measure specification
     */
    public static int getSize(int measureSpec) {
        return (measureSpec & ~MODE_MASK);
    }

    static int adjust(int measureSpec, int delta) {
        final int mode = getMode(measureSpec);
        int size = getSize(measureSpec);
        if (mode == UNSPECIFIED) {
            // No need to adjust size for UNSPECIFIED mode.
            return makeMeasureSpec(size, UNSPECIFIED);
        }
        size += delta;
        if (size < 0) {
            Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +
                    ") spec: " + toString(measureSpec) + " delta: " + delta);
            size = 0;
        }
        return makeMeasureSpec(size, mode);
    }

    /**
     * Returns a String representation of the specified measure
     * specification.
     *
     * @param measureSpec the measure specification to convert to a String
     * @return a String with the following format: "MeasureSpec: MODE SIZE"
     */
    public static String toString(int measureSpec) {
        int mode = getMode(measureSpec);
        int size = getSize(measureSpec);

        StringBuilder sb = new StringBuilder("MeasureSpec: ");

        if (mode == UNSPECIFIED)
            sb.append("UNSPECIFIED ");
        else if (mode == EXACTLY)
            sb.append("EXACTLY ");
        else if (mode == AT_MOST)
            sb.append("AT_MOST ");
        else
            sb.append(mode).append(" ");

        sb.append(size);
        return sb.toString();
    }
} 

It can be seen that MeasureSpec avoids excessive object memory allocation by packaging SpecMode and SpecSize into an int value. For convenience, it provides packaging and unpacking methods. SpecMode and SpecSize are also int values. A group of SpecMode and SpecSize can be packaged into a MeasureSpec, and a MeasureSpec can get the original SpecMode and SpecSize by unpacking. It should be noted that the MeasureSpec mentioned here refers to the int value represented by the MeasureSpec, not itself.

SpecMode

1.UNSPECIFIED

The parent container does not have any restrictions on the size of the View. This situation is generally used within the system to represent a measurement state

2.EXACTLY

The parent container has detected the exact size required by the View. At this time, the final size of the View is the value specified by SpecSize. It corresponds to match in LayoutParams_ Parent and specific value

3.ATMOST

The parent container specifies an available size, i.e. SpecSize. The size of the View cannot be greater than this value. The specific value depends on the specific implementation of different views. It corresponds to wrap in LayoutParams_ content

Corresponding relationship between MeasureSpec and LayoutParams

During View measurement, the system will convert LayoutParams into the corresponding MeasureSpec under the constraints of the parent container, and then determine the width and height after View measurement according to the MeasureSpec. It should be noted that the MeasureSpec is not the only one determined by LayoutParams. LayoutParams needs to work with the parent container to determine the MeasureSpec of the View, so as to further determine the width and height of the View. In addition, for DecorView and normal View, the conversion process of MeasureSpec is somewhat different. For a DecorView, its MeasureSpec is jointly determined by the window size and its own LayoutParams. For a normal View, its MeasureSpec is jointly determined by the MeasureSpec of the parent container and its own LayoutParams. After the MeasureSpec is determined, onMeasure can determine the measured width and height of the View.

As shown in the above figure, the measureHierarchy method in ViewRootImpl has the above code, which shows the creation process of MeasureSpec of DecorView, where desiredWindowWidth and desiredWindowHeight are the screen dimensions.

Implementation of getRootMeasureSpec method

The generation process of MeasureSpec of DecorView follows the following rules

1.LayoutParams.MATCH_PARENT: precise mode. The size is the size of the window. 2 LayoutParams. WRAP_ Content: maximum mode, variable size, but cannot exceed the window size 3 Fixed size: precise mode, the size is the size specified in layoutparams

For a normal View, the measure process of the View is passed from the ViewGroup. The following figure shows the measureChildWithMargins in the ViewGroup

The above method will measure the child element. Before calling the measure method of the child element, the MeasureSpec of the child element will be obtained through the getChildMeasureSpec method. The creation of MeasureSpec of child elements is related to the MeasureSpec of the parent container and the LayoutParams of the child element itself, as well as the margin and padding of the View.

The following figure shows the getChildMeasureSpec method of ViewGroup


Its main function is to determine the MeasureSpec of child elements according to the MeasureSpec of the parent container and the LayoutParams of the View itself. Padding in the parameter refers to the occupied space in the parent container. Therefore, the available size of child elements is the size of the parent container minus padding

MeasureSpec creation principle

The table sorts out the working principle of getChildMeasureSpec. Note that the parentSize in the table refers to the size currently available in the parent container

When the View has a fixed width and height, the MeasureSpec of the View is an exact mode regardless of the MeasureSpec of the parent container, and its size follows the size in LayoutParams.

When the width and height of View is match_ For parent, if the mode of the parent container is the precise mode, then the View is also the precise mode and its size is the remaining space of the parent container.

If the parent container mode is the maximum mode, then the View is also the maximum mode and its size will not exceed the remaining space of the parent container.

When the width and height of the View is wrap_content, regardless of whether the mode of the parent container is accurate or maximized, the mode of View is always maximized and the size cannot exceed the remaining space of the parent container.

end of document

Here, if you want to become an architect or take a step closer to technology, you should not be limited to coding and business, but be able to select, expand and improve programming thinking. In addition, good career planning is also very important. The habit of learning is very important, but the most important thing is to persevere. Any plan that cannot be implemented is empty talk.

If you have no direction, here is a set of advanced notes on the eight Android modules prepared by Ali senior architects to help you systematize the messy, scattered and fragmented knowledge, so that you can systematically and efficiently master all the knowledge points of Android development.

Compared with the fragmented content we usually read, the knowledge points of this note are more systematic, easier to understand and remember, and are arranged strictly according to the knowledge system.

1, Necessary skills for architects to build foundations

1. Deep understanding of Java generics
2. Notes in simple terms
3. Concurrent programming
4. Data transmission and serialization
5. Principles of Java virtual machine
6. High efficiency IO
......

2, Source code analysis of top 100 Android frameworks

1.retro 2.0 source code analysis
2.Okhttp3 source code analysis
3.ButterKnife source code analysis
4.mpadroidchart source code analysis
5.Glide source code analysis
6.Leakcanary source code analysis
7. Universal lmage loader source code analysis
8.EventBus 3.0 source code analysis
9.zxing source code analysis
10.Picasso source code analysis
11.LottieAndroid usage details and source code analysis
12.Fresco source code analysis - picture loading process

3, Practical analysis of Android performance optimization

  • Tencent Bugly: some understanding of string matching algorithm
  • Iqiyi: Android APP crash capture scheme - xCrash
  • Byte skipping: deeply understand one of the Gradle frameworks: Plugin, Extension, buildSrc
  • Baidu APP Technology: Android H5 first screen Optimization Practice
  • Alipay client architecture analysis: Android client startup speed optimization "garbage collection"
  • Ctrip: component architecture practice from the perspective of Zhixing Android project
  • Netease News Construction Optimization: how to make your construction speed "like lightning"?
  • ...

4, Advanced kotlin enhanced combat

1. Getting started with Kotlin
2. Kotlin practical pit avoidance Guide
3. Project practice "Kotlin Jetpack practice"

  • Start with a Demo of worshiping the great God

  • What was Kotlin's experience writing Gradle scripts?

  • Three realms of Kotlin programming

  • Kotlin higher order function

  • Kotlin generics

  • Kotlin extension

  • Entrusted by Kotlin

  • Debugging skills of "unknown" coordination process

  • Graphic collaboration: suspend

5, Advanced decryption of Android advanced UI open source framework

1. Use of smartrefreshlayout
2.Android PullToRefresh control source code analysis
3. Basic usage of Android pulltorefresh pull-down refresh Library
4.LoadSir- efficient and easy-to-use loading feedback page management framework
5. Detailed explanation of Android general LoadingView loading framework
6.mpadroidchart implements LineChart (line chart)
7. Hellocharts Android User Guide
8.SmartTable User Guide
9. introduction to the open source project Android uitableview
10.ExcelPanel User Guide
11. Deep analysis of Android open source project SlidingMenu
12.MaterialDrawer User Guide

6, NDK module development

1. NDK module development
2. JNI module
3. Native development tools
4. Linux Programming
5. Bottom picture processing
6. Audio and video development
7. Machine learning

7, Advanced shuttle Technology

1. Overview of Flutter cross platform development
2. Setup of the fluent development environment in Windows
3. Write your first shuttle app
4. Setup and debugging of Flutter development environment
5. Basic grammar of Dart Grammar (1)
6. The use and source code analysis of the collection of Dart Grammar (2)
7. Set operator functions and source code analysis in Dart Grammar (3)
...

8, Wechat applet development

1. Applet overview and introduction
2. Applet UI development
3. API operation
4. Shopping mall project practice

Full set of video materials:

1, Interview collection

2, Source code analysis collection


3, Open source framework collection


You are welcome to support three links with one button. If you need the information in the text, you can directly click on the official certified wechat card of CSDN at the end of the text to receive [guarantee 100% free] ↓↓

Tags: Android Android Studio

Posted by T.Stedel on Thu, 02 Jun 2022 23:30:58 +0530