onMeasure被执行两次原理解析

 更新时间:2023年02月07日 15:42:50   作者:Librity  
这篇文章主要为大家介绍了onMeasure被执行两次原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

什么情况下会onMeasure会执行?

进入Viewmeasure方法:

void measure(){
    boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
    boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec
        || heightMeasureSpec != mOldHeightMeasureSpec;
    boolean isSepcExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
        && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
    boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec)
        && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);
    final boolean needsLayout = specChanged
        && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize);
    if(forceLayout || needLayout){
        int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
        if (cacheIndex < 0 || sIgnoreMeasureCache) {
            onMeasure(widthMeasureSpec, heightMeasureSpec);
            mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
        } else {
            long value = mMeasureCache.valueAt(cacheIndex);
            setMeasuredDimensionRaw((int) (value >> 32), (int) value);
            mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
        }
   }
}

什么时候forceLayout=true:

  • 调用requestLayout
  • 调用forceRequestLayout

什么时候needsLayout=true:

  • 当长宽发生改变

什么时候调用了onMeasure>方法:

  • forceLayouy=true
  • 或者mMeasureCache没有当前的缓存

总结:

当调用了requestLayout一定会测发重测过程.当forceLayout=false的时候会去判断mMeasureCache值.现在研究下这个mMeasureCache

class View{
    LongSparseLongArray mMeasureCache;
    void measure(widthSpec,heightSpec){
        ---
        long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
        int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
        if(cacheIndex<0){
            onMeasure(widthSpec,heightSpec);
        }
        mOldWidthMeasureSpec = widthMeasureSpec;
        mOldHeightMeasureSpec = heightMeasureSpec;
        mMeasureCache.put(key,widhSpec|heightSpec);
        ---
    }
}

这里可以看到oldWidthMeasureSpecmMeasureCache都是缓存上一次的值,那他们有什么不同呢?不同点就是,oldWidthMeasureSpec>不仅仅缓存了测量的spec模式而且缓存了size.但是mMeasureCache只缓存了size.从这行代码可以看出:

long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;

这里一同运算就为了排除掉spec造成的影响.

//不信你可以试下下面的代码
public class Test {
    public static void main(String[] args) {
        long widthMeasureSpec = makeMeasureSpec(10,0);
        long heightMeasureSpec =  makeMeasureSpec(20,0);
        long ss = widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
        System.out.println("=========="+ss);
    }
    private static final int MODE_MASK = 0x3 << 30;
    public static int makeMeasureSpec(int size,
                                      int mode) {
        return (size & ~MODE_MASK) | (mode & MODE_MASK);
    }
}
//42949672980
//42949672980
//42949672980

什么时候mPrivateFlags会被赋值PFLAG_FORCE_LAYOUT.

view viewGrouup的构造函数里面会主动赋值一次,然后在ViewGroup.addView时候会给当前ViewmProvateFlags赋值PFLAG_FORCE_LAYOUT.

为什么onMeasure会被执行两次?

void measure(int widthMeasureSpec,int heightMeasureSpec){
    ----
    boolean forceLayout = (mPrivateFlags &amp; PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 
    if(forceLayout | needsLayout){
        onMeasure()
    }
    ----
}
public void layout(int l, int t, int r, int b){
    ---
    mPrivateFlags &amp;= ~PFLAG_FORCE_LAYOUT;
    ---
}

在第一次触发到measure方法时,forceLayoyt=true needsLayout=true,但是layout方法还没触发到.
在第二次触发到measure>方法时,forceLayout=true needsLayout=false,所以还是会进入onMeasure方法.这次会执行layout方法.然后我们在下次的时候forceLayout就等于false了.上面的这一段分析是分析的measure内部如何防止多次调用onMeasure.

分析外部是如何多次调用measure方法的

Activity执行到onResume生命周期的时候,会执行WindowManager.addView操作,WindowManager的具体实现类是WindowManagerImpl然后addView操作交给了代理类WindowManagerGlobal,然后在WindowManagerGlobaladdView里面执行了ViewRootImpl.setView操作(ViewRootImpl对象也是在这个时候创建的),在ViewRootImpl会主动调用一次requestLayout,也就开启了第一次的视图 测量 布局 绘制.

setView的时候主动调用了一次ViewRootImpl.requestLayout,注意这个requestLayoutViewRootImpl的内部方法,和view viewGroup那些requestLayout不一样.在ViewRootImpl.requestLayout内部调用了performTraversals方法:

class ViewRootImpl{
    void performTraversals(){
        if(layoutResuested){
        //标记1
            windowSizeMayChanged |= measureHierarchy(host,lp,res,desiredWindowWidth,desiredWindowHeight);
        }
        //标记2
        performMeasure()
        performLayout()
    }
    void measureHierarchy(){
        performMeasure()
    }
}

ViewRootImpl的执行逻辑你可以看出,在执行performLayout之前,他自己就已经调用了两次performMeasure方法.所以你现在就知道为啥了.

以上就是onMeasure被执行两次原理解析的详细内容,更多关于onMeasure被执行两次的资料请关注脚本之家其它相关文章!

相关文章

  • Android键盘自动弹出解决方法分析

    Android键盘自动弹出解决方法分析

    这篇文章主要介绍了Android键盘自动弹出解决方法,结合实例形式对比分析了三种解决方法,具有一定参考借鉴价值,需要的朋友可以参考下
    2016-01-01
  • Flutter给控件实现钻石般的微光特效

    Flutter给控件实现钻石般的微光特效

    这篇文章主要给大家介绍了关于Flutter给控件实现钻石般的微光特效的相关资料,实现的效果非常不错,非常适合大家做开发的时候参考,需要的朋友可以参考下
    2021-08-08
  • Android如何通过命令行操作Sqlite3数据库的方法

    Android如何通过命令行操作Sqlite3数据库的方法

    这篇文章主要介绍了Android如何通过命令行操作Sqlite3数据库的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Android实现单页面浮层可拖动view的一种方法

    Android实现单页面浮层可拖动view的一种方法

    本篇文章主要介绍了Android实现单页面浮层可拖动view的一种方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Android UI设计与开发之PopupWindow仿腾讯新闻底部弹出菜单

    Android UI设计与开发之PopupWindow仿腾讯新闻底部弹出菜单

    这篇文章主要为大家详细介绍了Android UI设计与开发之PopupWindow仿腾讯新闻底部弹出菜单,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • Android自定义View实现验证码

    Android自定义View实现验证码

    这篇文章主要为大家详细介绍了Android自定义View实现验证码的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • Android 轻松实现图片倒影效果实例代码

    Android 轻松实现图片倒影效果实例代码

    这篇文章主要介绍了Android 轻松实现图片倒影效果实例代码,有需要的朋友可以参考一下
    2014-01-01
  • Android小程序实现简易QQ界面

    Android小程序实现简易QQ界面

    这篇文章主要为大家详细介绍了Android小程序实现简易QQ界面,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • Android仿今日头条顶部导航栏效果的实例代码

    Android仿今日头条顶部导航栏效果的实例代码

    这篇文章主要介绍了Android之仿今日头条顶部导航栏效果的实例代码,具有很好的参考价值,希望对大家有所帮助,一起跟随小编过来看看吧
    2018-05-05
  • Kotlin结合Rxjava+Retrofit实现极简网络请求的方法

    Kotlin结合Rxjava+Retrofit实现极简网络请求的方法

    这篇文章主要给大家介绍了关于Kotlin结合Rxjava+Retrofit实现极简网络请求的相关内容,文中分别对Rxjava和Retrofit进行了简单的介绍,然后通过示例代码详细介绍了如何实现极简网络请求,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-11-11

最新评论