[Android FrameWork 6.0 source code learning] Measure and androidmeasure of View repainting process

Source: Internet
Author: User

[Android FrameWork 6.0 source code learning] Measure and androidmeasure of View repainting process

Trilogy of View painting, measurement, layout, painting
Today we analyze the measurement process

View measurement is initiated from ViewRootImpl. View needs to be re-painted, and all requests are sent to ViewRootImpl, which then organizes re-painting.
In the process of re-painting, one step is to measure and analyze the measurement process through code.

Private boolean measureHierarchy (final View host, final WindowManager. layoutParams lp, final Resources res, final int blocks, final int desired1_wheight) {int childWidthMeasureSpec; int blocks; boolean windowSizeMayChange = false; if (DEBUG_ORIENTATION | DEBUG_LAYOUT) Log. v (TAG, "Measuring" + host + "in display" + desired1_wwidth + "x" + desired1_wheight + "... "); Boolean goodMeasure = false; if (lp. width = ViewGroup. layoutParams. WRAP_CONTENT) {// On large screens, we don't want to allow dialogs to just // stretch to fill the entire width of the screen to display // one line of text. first try doing the layout at a smaller // size to see if it will fit. final DisplayMetrics packageMetrics = res. getDisplayMetrics (); res. getValue (com. android. interna L. r. dimen. config_prefDialogWidth, mTmpValue, true); int baseSize = 0; if (mTmpValue. type = TypedValue. TYPE_DIMENSION) {baseSize = (int) mTmpValue. getDimension (packageMetrics);} if (DEBUG_DIALOG) Log. v (TAG, "Window" + mView + ": baseSize =" + baseSize); if (baseSize! = 0 & desired1_wwidth> baseSize) {// gets the measurement specification, which is a 32-bit binary value. The first two digits indicate the mode, the last 30 digits indicate the length/width of the view. childWidthMeasureSpec = getRootMeasureSpec (baseSize, lp. width); childHeightMeasureSpec = getRootMeasureSpec (desired1_wheight, lp. height); // send a lifting painting scheme mmeasure (childWidthMeasureSpec, childHeightMeasureSpec) to DecorView; if (DEBUG_DIALOG) Log. v (TAG, "Window" + mView + ": measured (" + host. getMeasuredWidth () + "," + Host. getMeasuredHeight () + ")"); if (host. getMeasuredWidthAndState () & View. MEASURED_STATE_TOO_SMALL) = 0) {goodMeasure = true;} else {// Didn't fit in that size... try expanding a bit. baseSize = (baseSize + desired1_wwidth)/2; if (DEBUG_DIALOG) Log. v (TAG, "Window" + mView + ": next baseSize =" + baseSize); childWidthMeasureSpec = getRootMeasureSpec (baseSize, lp. width); implements mmeasure (c HildWidthMeasureSpec, childHeightMeasureSpec); if (DEBUG_DIALOG) Log. v (TAG, "Window" + mView + ": measured (" + host. getMeasuredWidth () + "," + host. getMeasuredHeight () + ")"); if (host. getMeasuredWidthAndState () & View. MEASURED_STATE_TOO_SMALL) = 0) {if (DEBUG_DIALOG) Log. v (TAG, "Good! "); GoodMeasure = true ;}}} if (! GoodMeasure) {childWidthMeasureSpec = getRootMeasureSpec (gradient, lp. width); gradient = getRootMeasureSpec (desired1_wheight, lp. height); gradient mmeasure (childWidthMeasureSpec, callback); if (mWidth! = Host. getMeasuredWidth () | mHeight! = Host. getMeasuredHeight () {windowSizeMayChange = true ;}} if (DBG) {System. out. println ("========================================== = "); system. out. println ("Maid mtraversals -- after measure"); host. debug ();} return windowSizeMayChange ;}

This function obtains the measurement specification through the getRootMeasureSpec method, and then calls the descrimmeasure method to distribute it to the entire view tree.

 

    private static int getRootMeasureSpec(int windowSize, int rootDimension) {        int measureSpec;        switch (rootDimension) {        case ViewGroup.LayoutParams.MATCH_PARENT:            // Window can't resize. Force root view to be windowSize.            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);            break;        case ViewGroup.LayoutParams.WRAP_CONTENT:            // Window can resize. Set max size for root view.            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);            break;        default:            // Window wants to be an exact size. Force root view to be that size.            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);            break;        }        return measureSpec;    }

 

Generate measurement specifications using the makeMeasureSpec method of MeasureSpec. First, determine whether the layout is match_parent, wrap_content, or a specified value.
Then pass windowSize.

    public static int makeMeasureSpec(int size, int mode) {            if (sUseBrokenMakeMeasureSpec) {                return size + mode;            } else {                return (size & ~MODE_MASK) | (mode & MODE_MASK);            }    }

 

If the API is greater than 17, else is used to judge the results. Helps to understand the subsequent operations

The calculation result of makeMeasureSpec is a 32-bit binary value. The first two digits indicate the measurement specification EXACTLY/AT_most, And the last 30 digits indicate windowSize. For example
Size = 320, mode = EXACTLY, which is converted to binary and is the two strings below.
Size = 0000 0000 0000 0000 0000 0001 0100
Mode = 0100 0000 0000 0000 0000 0000 0000
Mask = 1100 0000 0000 0000 0000 0000 0000 0000
Finally, the size and mode are integrated with the calculation.
0000 0000 0000 0000 0000 0001 0100 |
0100 0000 0000 0000 0000 0000 0000 =
0100 0000 0000 0000 0000 0001 0100

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");        try {            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);        } finally {            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }    }

 

This mView is the DecorView combined in the window class. This method calls the measure method of the view, and measure calls the OnMeasure method, and then implements the measurement of the entire view tree.

Public final void measure (int widthMeasureSpec, int heightMeasureSpec) {boolean optical = isLayoutModeOptical (this); if (optical! = IsLayoutModeOptical (mParent) {Insets insets = getOpticalInsets (); int oWidth = insets. left + insets. right; int oHeight = insets. top + insets. bottom; widthMeasureSpec = MeasureSpec. adjust (widthMeasureSpec, optical? -OWidth: oWidth); heightMeasureSpec = MeasureSpec. adjust (heightMeasureSpec, optical? -OHeight: oHeight);} // This piece Concatenates the width measurement specification and the height measurement specification, and serves as the key long key = (long) in the cache) widthMeasureSpec <32 | (long) heightMeasureSpec & 0 xffffffffL; if (mMeasureCache = null) mMeasureCache = new LongSparseLongArray (2); if (mPrivateFlags & tags) = PFLAG_FORCE_LAYOUT | widthMeasureSpec! = MOldWidthMeasureSpec | heightMeasureSpec! = MOldHeightMeasureSpec) {// first clears the measured dimension flag mPrivateFlags & = ~ PFLAG_MEASURED_DIMENSION_SET; resolveRtlPropertiesIfNeeded (); // determines whether to force measurement. If yes, call onMeasure again. The entire view tree will perform measurement again. Otherwise, the previous measurement specification will be obtained from the cache, // because DecorView is a subclass of FrameLayout, onMeasure is the onMeasure method that calls FrameLayout int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) = PFLAG_FORCE_LAYOUT? -1: mMeasureCache. indexOfKey (key); if (cacheIndex <0 | sIgnoreMeasureCache) {// measure ourselves, this shocould set the measured dimension flag back onMeasure (widthMeasureSpec, heigmeasurespec); done & = ~ PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;} else {long value = mMeasureCache. valueAt (cacheIndex); // Casting a long to int drops the high 32 bits, no mask needed // after calling this method, getMeasuredWidth and getMeasuredHeight can get the setMeasuredDimensionRaw (int) (value> 32), (int) value); mPrivateFlags3 | = random;} // flag not set, setMeasuredDimension () was not invoked, we raise // an e Xception to warn the developer if (mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET )! = PFLAG_MEASURED_DIMENSION_SET) {throw new IllegalStateException ("View with id" + getId () + ":" + getClass (). getName () + "# onMeasure () did not set the" + "measured dimension by calling" + "setMeasuredDimension ()");} mPrivateFlags | = callback;} mOldWidthMeasureSpec = widthMeasureSpec; mOldHeightMeasureSpec = heightMeasureSpec; // put the measurement specification to mMeasureCache in the set according to the fixed format. put (key, (long) mMeasuredWidth) <32 | (long) mMeasuredHeight & 0 xffffffffL); // suppress sign extension}

 

The function of this method is probably like this. First, determine whether there is a cache. If there is no cache, measure the entire tree, and then store it in the cache in a fixed format.

From here on, our entire measurement process starts to run.

Protected void onMeasure (int widthMeasureSpec, int limit) {int count = getChildCount (); // only the mode of match_parent and fixed width and height is EXACTLY, and wrap_content is AT_MOST final boolean Limit = MeasureSpec. getMode (widthMeasureSpec )! = MeasureSpec. EXACTLY | MeasureSpec. getMode (heightMeasureSpec )! = MeasureSpec. EXACTLY; mMatchParentChildren. clear (); int maxHeight = 0; // The height int maxWidth = 0 containing the padding; // The width int childState = 0 containing the width; // The first 16 bits indicate the width of the measurement mode, and the last 16 bits indicate the height of the Measurement mode. // all child for (int I = 0; I <count; I ++) {final View child = getChildAt (I); // the measurement range is if (mMeasureAllChildren | child. getVisibility ()! = GONE) {// when measuring a child, subtract the distance between padding and margin, get the child specification, call the child's measure, and then go back to the above analysis process, call child's onmeasurechildwithmargins (child, widthMeasureSpec, 0, heightMeasureSpec, 0); // assign values to maxWidth and maxHeight, and then use the getHeight and getWidth methods to final LayoutParams lp = (LayoutParams) child. getLayoutParams (); maxWidth = Math. max (maxWidth, child. getMeasuredWidth () + lp. leftMargin + lp. rightMargin); maxHeight = Math. Max (maxHeight, child. getMeasuredHeight () + lp. topMargin + lp. bottomMargin); childState = combineMeasuredStates (childState, child. getMeasuredState (); if (measureMatchParentChildren) {if (lp. width = LayoutParams. MATCH_PARENT | lp. height = LayoutParams. MATCH_PARENT) {mMatchParentChildren. add (child) ;}}}// Account for padding too maxWidth + = getPaddingLeftWithForeground () + getPaddingRightW IthForeground (); maxHeight + = getPaddingTopWithForeground () + getPaddingBottomWithForeground (); // Check against our minimum height and width maxHeight = Math. max (maxHeight, getSuggestedMinimumHeight (); maxWidth = Math. max (maxWidth, getSuggestedMinimumWidth (); // Check against our foreground's minimum height and width final Drawable drawable = getForeground (); if (drawable! = Null) {maxHeight = Math. max (maxHeight, drawable. getMinimumHeight (); maxWidth = Math. max (maxWidth, drawable. getMinimumWidth ();} // set the measurement result setMeasuredDimension (Measures (maxWidth, widthMeasureSpec, childState), resolveSizeAndState (maxHeight, heightMeasureSpec, childState <condition) of the subspace )); // start to measure the width and height of MATCH_PARENT layout count = mMatchParentChildren. size (); if (count> 1) {for (int I = 0; I <count; I ++) {final View child = mMatchParentChildren. get (I); final MarginLayoutParams lp = (MarginLayoutParams) child. getLayoutParams (); final int childWidthMeasureSpec; if (lp. width = LayoutParams. MATCH_PARENT) {final int width = Math. max (0, getMeasuredWidth ()-getPaddingLeftWithForeground ()-getPaddingRightWithForeground ()-lp. leftMargin-lp. rightMargin); childWidthMeasureSpec = MeasureSpec. makeMeasureSpec (width, MeasureSpec. EXACTLY);} else {childWidthMeasureSpec = getChildMeasureSpec (widthMeasureSpec, getPaddingLeftWithForeground () + getPaddingRightWithForeground () + lp. leftMargin + lp. rightMargin, lp. width);} final int childHeightMeasureSpec; if (lp. height = LayoutParams. MATCH_PARENT) {final int height = Math. max (0, getMeasuredHeight ()-getPaddingTopWithForeground ()-getPaddingBottomWithForeground ()-lp. topMargin-lp. bottomMargin); childHeightMeasureSpec = MeasureSpec. makeMeasureSpec (height, MeasureSpec. EXACTLY);} else {childHeightMeasureSpec = getChildMeasureSpec (heightMeasureSpec, getPaddingTopWithForeground () + getPaddingBottomWithForeground () + lp. topMargin + lp. bottomMargin, lp. height);} child. measure (childWidthMeasureSpec, childHeightMeasureSpec );}}}

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.