Read The Fucking Source Code

The introduction

When choosing a layout, you must consider a comparative advantage of performance.

Android Q — API 29

1 FrameLayout onMeasure

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); // As long as the FrameLayout layout has wrap_content (only it is not EXACTLY mode) // then a second measurement is possible for child views with match_parent set. And why? I was lost in thought. final boolean measureMatchParentChildren = MeasureSpec.getMode(widthMeasureSpec) ! = MeasureSpec.EXACTLY || MeasureSpec.getMode(heightMeasureSpec) ! = MeasureSpec.EXACTLY; mMatchParentChildren.clear(); int maxHeight = 0; int maxWidth = 0; int childState = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); //mMeasureAllChildren XML configurable item. Default is false. The main function is: whether to measure the GONE child View. / / so this logic becomes the traverse each for GONE no children view the if (mMeasureAllChildren | | child. The getVisibility ()! // Remove the left/right padding of FrameLayout and the left/right margin of the child View. MeasureChildWithMargins (Child, widthMeasureSpec, 0, heightMeasureSpec, 0); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); // Find and save the maximum width/height in the subview. This is the property of FrameLayout. // When FrameLayout is wrap_content, its width and height are limited by the maximum width and height of the child View. // We all know that views with wrap_content (AT_MOST) have no subsequent measurement constraint (onMeasure redefinition), and the default is match_parent effect. // For example: wrap_content FrameLayout contains a wrap_content View, then FrameLayout is the full screen size. // For example: wrap_content FrameLayout contains a View that is 200 width and height, so FrameLayout is 200 width and height. maxWidth = Math.max(maxWidth, child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); // The policy state of the subview is merged to the policy state of FrameLayout. childState = combineMeasuredStates(childState, child.getMeasuredState()); // Cache the child View with MATCH_PARENT. if (measureMatchParentChildren) { if (lp.width == LayoutParams.MATCH_PARENT || lp.height == LayoutParams.MATCH_PARENT) {  mMatchParentChildren.add(child); }}}} // The maximum width and height of the subview plus the panding information is the width and height of FrameLayout. maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground(); maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground(); / / check the minimum height and width, we take the biggest maxHeight = math.h Max (maxHeight, getSuggestedMinimumHeight ()); maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); Final Drawable Drawable = getForeground(); if (drawable ! = null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } // Set the measurement width and height of FrameLayout. // If FrameLayout is not wrap_content, its size is either the set size (say 200) or the full screen (full parent) size (match_parent). // If FrameLayout is wrap_content, set it to the maximum child view width/height if the full screen width/height is greater than or equal to the maximum child view width/height, otherwise set it to the full screen width/height. // In short, take the smallest of maxWidth (traversing the child and checking the parent's configuration, the maximum desired width) and widthMeasureSpec (the maximum allowed parent's width). setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT)); / / the number of child View Settings match_parent properties count = mMatchParentChildren. The size (); // When the number of child views with match_parent is greater than 1. And why? Again, I was lost in thought. If (count > 1) {// Go through each child view and get the MeasureSpec property differently for match_parent. Personally, it doesn't make any difference. I'm thinking again... 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); }}}Copy the code

2 Summary summary

  • FrameLayout’s layout measurement is simple and efficient (no special scenarios are considered), and only measured once.
  • FrameLayout is measured twice in special cases (when the FrameLayout root layout has wrap_content and the number of child views (with match_parent) is greater than one).
  • Foreground properties, which are unique in FrameLayout, enable the foreground color of the clicked state, as well as the splash screen set up like Windows Contentoverlay in DecorView.

3 Problem Thinking

Framelayout’s simple and efficient layout performance features are widely used.

  • For example, the content and layout of a DecorView are FrameLayout.
  • FrameLayout How to avoid measuring twice?

When using FrameLayout, try not to satisfy the condition of measuring twice. Use wrap_content instead of match_parent if the child View wants to fill the screen (fill the parent container).

Xiaobian extension links

Android View Module Family Bucket