欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

onMeasure被執(zhí)行兩次原理解析

 更新時間:2023年02月07日 15:42:50   作者:Librity  
這篇文章主要為大家介紹了onMeasure被執(zhí)行兩次原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

什么情況下會onMeasure會執(zhí)行?

進入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:

  • 當長寬發(fā)生改變

什么時候調用了onMeasure>方法:

  • forceLayouy=true
  • 或者mMeasureCache沒有當前的緩存

總結:

當調用了requestLayout一定會測發(fā)重測過程.當forceLayout=false的時候會去判斷mMeasureCache值.現(xiàn)在研究下這個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的構造函數(shù)里面會主動賦值一次,然后在ViewGroup.addView時候會給當前ViewmProvateFlags賦值PFLAG_FORCE_LAYOUT.

為什么onMeasure會被執(zhí)行兩次?

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;
    ---
}

在第一次觸發(fā)到measure方法時,forceLayoyt=true needsLayout=true,但是layout方法還沒觸發(fā)到.
在第二次觸發(fā)到measure>方法時,forceLayout=true needsLayout=false,所以還是會進入onMeasure方法.這次會執(zhí)行layout方法.然后我們在下次的時候forceLayout就等于false了.上面的這一段分析是分析的measure內部如何防止多次調用onMeasure.

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

Activity執(zhí)行到onResume生命周期的時候,會執(zhí)行WindowManager.addView操作,WindowManager的具體實現(xiàn)類是WindowManagerImpl然后addView操作交給了代理類WindowManagerGlobal,然后在WindowManagerGlobaladdView里面執(zhí)行了ViewRootImpl.setView操作(ViewRootImpl對象也是在這個時候創(chuàng)建的),在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的執(zhí)行邏輯你可以看出,在執(zhí)行performLayout之前,他自己就已經(jīng)調用了兩次performMeasure方法.所以你現(xiàn)在就知道為啥了.

以上就是onMeasure被執(zhí)行兩次原理解析的詳細內容,更多關于onMeasure被執(zhí)行兩次的資料請關注腳本之家其它相關文章!

相關文章

最新評論