網(wǎng)站首頁 編程語言 正文
什么情況下會onMeasure會執(zhí)行?
進入View
的measure
方法:
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
:
- 調(diào)用
requestLayout
- 調(diào)用
forceRequestLayout
什么時候needsLayout=true
:
- 當長寬發(fā)生改變
什么時候調(diào)用了onMeasure>
方法:
forceLayouy=true
- 或者
mMeasureCache
沒有當前的緩存
總結(jié):
當調(diào)用了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); --- } }
這里可以看到oldWidthMeasureSpec
和mMeasureCache
都是緩存上一次的值,那他們有什么不同呢?不同點就是,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
的構(gòu)造函數(shù)里面會主動賦值一次,然后在ViewGroup.addView
時候會給當前View
的mProvateFlags
賦值PFLAG_FORCE_LAYOUT
.
為什么onMeasure會被執(zhí)行兩次?
void measure(int widthMeasureSpec,int heightMeasureSpec){ ---- boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; if(forceLayout | needsLayout){ onMeasure() } ---- } public void layout(int l, int t, int r, int b){ --- mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; --- }
在第一次觸發(fā)到measure
方法時,forceLayoyt=true needsLayout=true
,但是layout
方法還沒觸發(fā)到.
在第二次觸發(fā)到measure>
方法時,forceLayout=true needsLayout=false
,所以還是會進入onMeasure
方法.這次會執(zhí)行layout
方法.然后我們在下次的時候forceLayout
就等于false
了.上面的這一段分析是分析的measure
內(nèi)部如何防止多次調(diào)用onMeasure
.
分析外部是如何多次調(diào)用measure方法的
在Activity
執(zhí)行到onResume
生命周期的時候,會執(zhí)行WindowManager.addView
操作,WindowManager
的具體實現(xiàn)類是WindowManagerImpl
然后addView
操作交給了代理類WindowManagerGlobal
,然后在WindowManagerGlobal
的addView
里面執(zhí)行了ViewRootImpl.setView
操作(ViewRootImpl
對象也是在這個時候創(chuàng)建的),在ViewRootImpl
會主動調(diào)用一次requestLayout
,也就開啟了第一次的視圖 測量 布局 繪制.
在setView
的時候主動調(diào)用了一次ViewRootImpl.requestLayout
,注意這個requestLayout
是ViewRootImpl
的內(nèi)部方法,和view viewGroup
那些requestLayout
不一樣.在ViewRootImpl.requestLayout
內(nèi)部調(diào)用了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)調(diào)用了兩次performMeasure
方法.所以你現(xiàn)在就知道為啥了.
原文鏈接:https://juejin.cn/post/7197116653195624508
相關(guān)推薦
- 2022-05-17 python的列表生成式,生成器和generator對象你了解嗎_python
- 2022-10-03 利用正則表達式校驗金額最多保留兩位小數(shù)實例代碼_正則表達式
- 2022-07-03 C#并行編程之PLINQ(并行LINQ)_C#教程
- 2023-07-25 npm login 時報錯npm ERR! code E403
- 2022-03-30 C語言入門之淺談數(shù)據(jù)類型和變量常量_C 語言
- 2022-06-12 Pandas對CSV文件讀寫操作詳解_python
- 2022-04-08 從頭學習C語言之指針和數(shù)組_C 語言
- 2022-07-27 python如何查找列表中元素的位置_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支