作为一名Android开发人员,我们都知道一个View从无到有,会经历3个阶段:

1. measure/测量阶段,也就是确定某个view大小的过程;

2. layout/布局阶段,也就是确定其左上右下坐标的过程;

3. draw/绘制阶段,也就是按照前面2步计算的结果,将view绘制在屏幕相应的位置上;

今天,我带领大家来看看View系统的measure过程。到现在相信大部分人都知道measure是从ViewRootImpl.measureHierarchy

方法开始的,但归根结底是从performTraversals开始的。

  为了从一开始就清楚onMeasure(int widthMeasureSpec, int heightMeasureSpec)的这2个参数从哪来的,虽然我们都知道

这2个参数表示parent施加给我们的约束,但可能大部分人不明白程序run起来的时候这些值都是从哪里来的。为了弄清楚这个问题,

我们还得从上面ViewRootImpl的measureHierarchy说起,来看其源码:

    private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {int childWidthMeasureSpec;int childHeightMeasureSpec;boolean windowSizeMayChange = false;if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,"Measuring " + host + " in display " + desiredWindowWidth+ "x" + desiredWindowHeight + "...");boolean goodMeasure = false;if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { // 在WRAP_CONTENT的情况下,先从一个prefered值开始measure// 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.internal.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 && desiredWindowWidth > baseSize) { // 如果baseSize真小的话,用baseSize先measure一遍试试childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("+ host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {goodMeasure = true; // measure的结果合适} else {// Didn't fit in that size... try expanding a bit.baseSize = (baseSize+desiredWindowWidth)/2; // 加大baseSize重新执行上述过程if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="+ baseSize);childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);performMeasure(childWidthMeasureSpec, 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) { // 如果用baseSize measure的结果不合适,则老老实实用提供的参数重新measure一遍childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {windowSizeMayChange = true;}}if (DBG) {System.out.println("======================================");System.out.println("performTraversals -- after measure");host.debug();}return windowSizeMayChange;}/*** Figures out the measure spec for the root view in a window based on it's* layout params.** @param windowSize*            The available width or height of the window** @param rootDimension*            The layout params for one dimension (width or height) of the*            window.** @return The measure spec to use to measure the root view.*/private static int getRootMeasureSpec(int windowSize, int rootDimension) { // 通过具体的windowSize和提供的specint measureSpec;                                                       // 构造一个合适的Root MeasureSpecswitch (rootDimension) {  // 这里的windowSize就是设备的宽、高,rootDimension就是xml文件里指定的layoutparamcase ViewGroup.LayoutParams.MATCH_PARENT:// Window can't resize. Force root view to be windowSize. 设置root view就是window这么大measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);break;case ViewGroup.LayoutParams.WRAP_CONTENT:// Window can resize. Set max size for root view. 设置root view最多是window这么大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;}

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");try {            // 调用root view的measure方法,从此进入到view层次结构,顺便也把MeasureSpec带了进去。。。mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);} finally {Trace.traceEnd(Trace.TRACE_TAG_VIEW);}}

  从之前的文章中,我们知道DecorView实际上是继承至FrameLayout,由于它和ViewGroup都没有重载这个方法,实际上也没法重载,

因为这个方法是View的一个final方法,代码如下:

/*** <p>* This is called to find out how big a view should be. The parent* supplies constraint information in the width and height parameters.* </p>** <p>* The actual measurement work of a view is performed in* {@link #onMeasure(int, int)}, called by this method. Therefore, only* {@link #onMeasure(int, int)} can and must be overridden by subclasses.* </p>*** @param widthMeasureSpec Horizontal space requirements as imposed by the*        parent* @param heightMeasureSpec Vertical space requirements as imposed by the*        parent** @see #onMeasure(int, int)*/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);}// Suppress sign extension for the low byteslong key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||widthMeasureSpec != mOldWidthMeasureSpec ||heightMeasureSpec != mOldHeightMeasureSpec) {// first clears the measured dimension flagmPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;resolveRtlPropertiesIfNeeded();int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :mMeasureCache.indexOfKey(key);if (cacheIndex < 0 || sIgnoreMeasureCache) {// measure ourselves, this should set the measured dimension flag backonMeasure(widthMeasureSpec, heightMeasureSpec); // 注意这个调用,这个方法是本文的重点mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;} else {long value = mMeasureCache.valueAt(cacheIndex);// Casting a long to int drops the high 32 bits, no mask neededsetMeasuredDimension((int) (value >> 32), (int) value);mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;}// flag not set, setMeasuredDimension() was not invoked, we raise// an exception to warn the developerif ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {throw new IllegalStateException("onMeasure() did not set the"+ " measured dimension by calling"+ " setMeasuredDimension()");}mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;}mOldWidthMeasureSpec = widthMeasureSpec;mOldHeightMeasureSpec = heightMeasureSpec;mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |(long) mMeasuredHeight & 0xffffffffL); // suppress sign extension}

正如方法doc说的那样,真正的measure过程是发生在onMeasure方法中的,所以你可以也应该override这个方法,我们紧接着看看View中

的默认实现,代码如下:

    /*** <p>* Measure the view and its content to determine the measured width and the* measured height. This method is invoked by {@link #measure(int, int)} and* should be overriden by subclasses to provide accurate and efficient* measurement of their contents.* </p>** <p>* <strong>CONTRACT:</strong> When overriding this method, you* <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the* measured width and height of this view. Failure to do so will trigger an* <code>IllegalStateException</code>, thrown by* {@link #measure(int, int)}. Calling the superclass'* {@link #onMeasure(int, int)} is a valid use.* </p>** <p>* The base class implementation of measure defaults to the background size,* unless a larger size is allowed by the MeasureSpec. Subclasses should* override {@link #onMeasure(int, int)} to provide better measurements of* their content.* </p>** <p>* If this method is overridden, it is the subclass's responsibility to make* sure the measured height and width are at least the view's minimum height* and width ({@link #getSuggestedMinimumHeight()} and* {@link #getSuggestedMinimumWidth()}).* </p>** @param widthMeasureSpec horizontal space requirements as imposed by the parent.*                         The requirements are encoded with*                         {@link android.view.View.MeasureSpec}.* @param heightMeasureSpec vertical space requirements as imposed by the parent.*                         The requirements are encoded with*                         {@link android.view.View.MeasureSpec}.** @see #getMeasuredWidth()* @see #getMeasuredHeight()* @see #setMeasuredDimension(int, int)* @see #getSuggestedMinimumHeight()* @see #getSuggestedMinimumWidth()* @see android.view.View.MeasureSpec#getMode(int)* @see android.view.View.MeasureSpec#getSize(int)*/protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}/*** <p>This method must be called by {@link #onMeasure(int, int)} to store the* measured width and measured height. Failing to do so will trigger an* exception at measurement time.</p>** @param measuredWidth The measured width of this view.  May be a complex* bit mask as defined by {@link #MEASURED_SIZE_MASK} and* {@link #MEASURED_STATE_TOO_SMALL}.* @param measuredHeight The measured height of this view.  May be a complex* bit mask as defined by {@link #MEASURED_SIZE_MASK} and* {@link #MEASURED_STATE_TOO_SMALL}.*/protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {boolean optical = isLayoutModeOptical(this);if (optical != isLayoutModeOptical(mParent)) {Insets insets = getOpticalInsets();int opticalWidth  = insets.left + insets.right;int opticalHeight = insets.top  + insets.bottom;measuredWidth  += optical ? opticalWidth  : -opticalWidth;measuredHeight += optical ? opticalHeight : -opticalHeight;}mMeasuredWidth = measuredWidth; // 赋值mMeasuredHeight = measuredHeight;mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; // 设置标志位}/*** Returns the suggested minimum height that the view should use. This* returns the maximum of the view's minimum height* and the background's minimum height* ({@link android.graphics.drawable.Drawable#getMinimumHeight()}).* <p>* When being used in {@link #onMeasure(int, int)}, the caller should still* ensure the returned height is within the requirements of the parent.** @return The suggested minimum height of the view.*/protected int getSuggestedMinimumHeight() {// 找到view的最小大小,没background的时候返回mMinHeight,这个你可以在xml中指定return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());// 否则返回mMinHeight和background的最小值里的较大者}/*** Returns the suggested minimum width that the view should use. This* returns the maximum of the view's minimum width)* and the background's minimum width*  ({@link android.graphics.drawable.Drawable#getMinimumWidth()}).* <p>* When being used in {@link #onMeasure(int, int)}, the caller should still* ensure the returned width is within the requirements of the parent.** @return The suggested minimum width of the view.*/protected int getSuggestedMinimumWidth() {return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());}/*** Utility to return a default size. Uses the supplied size if the* MeasureSpec imposed no constraints. Will get larger if allowed* by the MeasureSpec.** @param size Default size for this view* @param measureSpec Constraints imposed by the parent* @return The size this view should be.*/public static int getDefaultSize(int size, int measureSpec) {int result = size;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) {case MeasureSpec.UNSPECIFIED: // parent imposed的spec没指定,则用自己的值default sizeresult = size;break;case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY: // 否则不论是精确指定或是至多,都用spec提供的值result = specSize;break;}return result;}

我们看到View.onMeasure方法只是提供了一个通用的、一般的实现,子类一般需要重载它,自己提供更加合理、高效的实现,最重要的是

符合你的需求。同时我们也看到ViewGroup并没有提供它自己的实现,但是提供了一些在measure过程中很有用的方法,其特定子类如

FrameLayout、LinearLayout等在measure过程中都需要用到的。

  为了更进一步看看这个过程,我们这里以FrameLayout的onMeasure为例分析下,看其源码:

    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int count = getChildCount();// matchparent child标记final boolean measureMatchParentChildren =MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;mMatchParentChildren.clear(); // 清空列表int maxHeight = 0;int maxWidth = 0;int childState = 0;// 遍历children,初步找出maxHeight和maxWidth,顺便构造mMatchParentChildren列表for (int i = 0; i < count; i++) {final View child = getChildAt(i);            // 默认情况下,只measure非GONE的child,但你可以设置mMeasureAllChildren来打破这一限制if (mMeasureAllChildren || child.getVisibility() != GONE) {                // 调用parent,ViewGroup提供的方法。。。measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);                // 我们平时在xml文件中设置的android:layout_xxx其实就是这里的LayoutParamsfinal 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); // 添加matchparent child}}}}// 进一步调整maxWidth、maxHeight的值,考虑foreground padding、minimum height/width,还有foreground的最小值// Account for padding toomaxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();// Check against our minimum height and widthmaxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());// Check against our foreground's minimum height and widthfinal Drawable drawable = getForeground();if (drawable != null) {maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());}// 设置FrameLayout自身的measuredWidth、measuredHeightsetMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),resolveSizeAndState(maxHeight, heightMeasureSpec,childState << MEASURED_HEIGHT_STATE_SHIFT));count = mMatchParentChildren.size();if (count > 1) { // 如果有matchparent child的话for (int i = 0; i < count; i++) {final View child = mMatchParentChildren.get(i);final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidthMeasureSpec;int childHeightMeasureSpec;if (lp.width == LayoutParams.MATCH_PARENT) {                    // 如果是MATCH_PARENT的话,由于parent已经measure过了,所以就相当于child指定了确定值,                    // 所以用的MeasureSpec.EXACTLY。。。childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -getPaddingLeftWithForeground() - getPaddingRightWithForeground() -lp.leftMargin - lp.rightMargin,// 在算child大小的时候要去掉parent的padding,child自己指定的各种marginMeasureSpec.EXACTLY);} else {                    // 否则,根据parent的measureSpec,已经用掉的大小,child的layoutparam的信息,创建一个合适的MeasureSpecchildWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,getPaddingLeftWithForeground() + getPaddingRightWithForeground() +lp.leftMargin + lp.rightMargin,lp.width);}if (lp.height == LayoutParams.MATCH_PARENT) {childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -getPaddingTopWithForeground() - getPaddingBottomWithForeground() -lp.topMargin - lp.bottomMargin,MeasureSpec.EXACTLY);} else {childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,getPaddingTopWithForeground() + getPaddingBottomWithForeground() +lp.topMargin + lp.bottomMargin,lp.height);}// 用新的childWidthMeasureSpec、childHeightMeasureSpec再次measure childchild.measure(childWidthMeasureSpec, childHeightMeasureSpec);}}}

  接下来,我们重点看看涉及到的几个ViewGroup方法,代码如下:

    /*** Ask one of the children of this view to measure itself, taking into* account both the MeasureSpec requirements for this view and its padding* and margins. The child must have MarginLayoutParams The heavy lifting is* done in getChildMeasureSpec.** @param child The child to measure* @param parentWidthMeasureSpec The width requirements for this view* @param widthUsed Extra space that has been used up by the parent*        horizontally (possibly by other children of the parent)* @param parentHeightMeasureSpec The height requirements for this view* @param heightUsed Extra space that has been used up by the parent*        vertically (possibly by other children of the parent)*/protected void measureChildWithMargins(View child,int parentWidthMeasureSpec, int widthUsed,int parentHeightMeasureSpec, int heightUsed) {final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin // 考虑上parent的padding和child的margin+ widthUsed, lp.width);final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin+ heightUsed, lp.height);// 这里如果child是个ViewGroup类型,则实际会递归下去。。。child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}/*** Does the hard part of measureChildren: figuring out the MeasureSpec to* pass to a particular child. This method figures out the right MeasureSpec* for one dimension (height or width) of one child view.** The goal is to combine information from our MeasureSpec with the* LayoutParams of the child to get the best possible results. For example,* if the this view knows its size (because its MeasureSpec has a mode of* EXACTLY), and the child has indicated in its LayoutParams that it wants* to be the same size as the parent, the parent should ask the child to* layout given an exact size.** @param spec The requirements for this view* @param padding The padding of this view for the current dimension and*        margins, if applicable* @param childDimension How big the child wants to be in the current*        dimension* @return a MeasureSpec integer for the child*/ public static int getChildMeasureSpec(int spec, int padding, int childDimension) {        // 这个方法是协商型的,最终结果既可能直接由spec(parent提供的),也可能由childDimension决定        // 所以我们知道了,一个View的大小不是简单的单方面决定的,而是通过一系列条件协商的结果,        // 有时会尊重parent的spec,有时会坚持自己的dimension要求int specMode = MeasureSpec.getMode(spec);int specSize = MeasureSpec.getSize(spec);int size = Math.max(0, specSize - padding); // 可用的大小int resultSize = 0;int resultMode = 0;switch (specMode) {// Parent has imposed an exact size on uscase MeasureSpec.EXACTLY: // parent说child你应该是个确定的大小if (childDimension >= 0) { // child正好设置了确定的大小resultSize = childDimension; // 让child是那个确定的大小resultMode = MeasureSpec.EXACTLY; // 设置mode为EXACTLY} else if (childDimension == LayoutParams.MATCH_PARENT) {// Child wants to be our size. So be it.resultSize = size; // 其他情况下都是parent spec中的大小,只是mode不同resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.WRAP_CONTENT) {// Child wants to determine its own size. It can't be// bigger than us.resultSize = size; // 不能超过sizeresultMode = MeasureSpec.AT_MOST;}break;// Parent has imposed a maximum size on uscase MeasureSpec.AT_MOST: // parent说child你应该最大是某个值。。。if (childDimension >= 0) { // child指定确定值了,则听child的// Child wants a specific size... so be itresultSize = childDimension;resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) {// Child wants to be our size, but our size is not fixed.// Constrain child to not be bigger than us.resultSize = size;resultMode = MeasureSpec.AT_MOST;} else if (childDimension == LayoutParams.WRAP_CONTENT) {// Child wants to determine its own size. It can't be// bigger than us.resultSize = size;resultMode = MeasureSpec.AT_MOST;}break;// Parent asked to see how big we want to becase MeasureSpec.UNSPECIFIED: // parent没对child的大小有啥要求if (childDimension >= 0) { // child指定了确定的值,听child的// Child wants a specific size... let him have itresultSize = childDimension;resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) {// Child wants to be our size... find out how big it should// beresultSize = 0;resultMode = MeasureSpec.UNSPECIFIED;} else if (childDimension == LayoutParams.WRAP_CONTENT) {// Child wants to determine its own size.... find out how// big it should beresultSize = 0;resultMode = MeasureSpec.UNSPECIFIED;}break;}return MeasureSpec.makeMeasureSpec(resultSize, resultMode);}

  至此我们已经将measure过程的相关代码大致分析了下,进一步的理解还需要大家在开发中慢慢体会、细细研读源码,最后附上一篇

不错的同主题文章:http://www.cnblogs.com/xilinch/archive/2012/10/24/2737178.html。

转载于:https://www.cnblogs.com/dongweiq/p/3971348.html

Android measure过程分析相关推荐

  1. cm-14.1 Android系统启动过程分析(4)-init进程的启动、rc脚本解析、zygote启动、属性服务

    声明 前阶段在项目中涉及到了Android系统定制任务,Android系统定制前提要知道Android系统是如何启动的. 本文参考了一些书籍的若干章节,比如<Android进阶解密-第2章-An ...

  2. [日更-2019.4.8、4.9、4.12、4.13] cm-14.1 Android系统启动过程分析(一)-init进程的启动、rc脚本解析、zygote启动、属性服务...

    2019独角兽企业重金招聘Python工程师标准>>> 声明 前阶段在项目中涉及到了Android系统定制任务,Android系统定制前提要知道Android系统是如何启动的. 本文 ...

  3. cm-14.1 Android系统启动过程分析(8)-应用程序进程启动过程

    文章目录 声明 0 写在前面 1 什么应用程序进程? 2 应用程序进程的启动过程 2.1 AMS发送启动应用程序进程请求 2.2 Zygote接收AMS的请求并创建应用程序进程 3 启动线程池 4 创 ...

  4. [日更-2019.4.26、27、28] cm-14.1 Android系统启动过程分析(四)-应用程序进程启动过程...

    2019独角兽企业重金招聘Python工程师标准>>> 声明 前阶段在项目中涉及到了Android系统定制任务,Android系统定制前提要知道Android系统是如何启动的: 本文 ...

  5. Android measure方法详解

    1. MeasureSpec类 MeasureSpec用来计算子视图的大小,有三种类型,UNSPECIFIED.EXACTLY和AT_MOST. UNSPECIFIED表示未定义,即父控件未做限制,可 ...

  6. cm-14.1 Android系统启动过程分析(3) - Android系统启动流程概述

    声明 前阶段在项目中涉及到了Android系统定制任务,Android系统定制前提要知道Android系统是如何启动的. 本文参考了一些书籍的若干章节,比如<Android进阶解密-第2章-An ...

  7. Android onMeasure过程分析

    测量布局开始的总入口: android.view.ViewRootImpl#measureHierarchy 里面调用了performMeasure private boolean measureHi ...

  8. android measure的时候报空指针

    1.使用listview的时候,在代码中动态设置其高度,在android低版本中,这个低版本是以4.4为界,会报measure的空指针,原因是低版本relativelayout有个bug,使用list ...

  9. android layout过程分析,Andriod 从 0 开始自定义控件之 View 的 layout 过程 (八)

    前言 在上一篇文章了,我们学习了 View 三大流程之一的 measure 过程,当 measure 过程完成后,View 的大小就测量好了.接下来就到了 layout 的过程了,layout 的过程 ...

  10. android measure

    首先 onMeasure方法是为了得到各个View大小的函数 fill_parent-->public static final int EXACTLY = 1 << MODE_SH ...

最新文章

  1. zzUbuntu安装配置Qt环境
  2. Android 省,市,区选择权
  3. php 剪贴板,之Windows中的剪贴板
  4. PWN-PRACTICE-BUUCTF-19
  5. 使用Win Server 2012 R2的IIS创建FTP
  6. (24)System Verilog多个线程间通信(信箱)
  7. Spring Boot Mybatis简单使用
  8. 用Netfilter模块实现基于令牌桶的每IP地址流量控制
  9. python有什么用-我们为什么要选择学习python?学习python有什么用?
  10. pygame重新开始_Pygame(十八)音乐
  11. 知识图谱最新研究综述
  12. Codeforces Round #568 (Div. 2)网卡垫底记
  13. mybatis主键是在insert前生成还是之后生成
  14. Bex5开发技巧之如何在列表中显示主键字段
  15. 可编程、变频调速与触摸屏实验实训装置
  16. kylo添加登录权限module
  17. VMware下linux ubuntu 虚拟机复制粘贴-宿主机
  18. 线代 | 矩阵的迹 向量内积如何转化为迹
  19. i.max6 e9 android系统添加3G模块支持 上
  20. Tixati——BT下载软件

热门文章

  1. Google 中国开发者大会最后一天报名!
  2. 《Android 面试指南》来自腾讯、阿里巴巴、欢聚时代、美团、聚美优品、悦跑圈等大佬分享的面经...
  3. Google 又有新动作了
  4. Treap 树堆 容易实现的平衡树
  5. es6箭头函数使用场景导致的一些问题
  6. STM32F0xx_TIM基本延时配置详细过程
  7. Silverlight 里获取摄像头视频
  8. SHA1withRSA加签名和验签名
  9. linux运维命令3
  10. hdu-1521 排列组合 指数型母函数