成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

View.post() 不靠譜的地方你知道嗎?

開發 開發工具
View.post() 方法,在不同版本的差異,根本原因還是在于 Api23 和 Api24 中,executeActions() 方法的調用時機不同,導致 View 在沒有 mAttachInfo 對象的時候,表現不一樣了。

這篇文章之前發過一遍,但是有讀者指出來有些地方描述的有問題,我后來再看的時候也覺得有問題,所以把之前的文章刪掉(主線是沒有問題的,刪掉只是是避免更多的人誤會),準備修改勘誤之后,再重新發布一遍,這次會補齊描述問題的 Demo 。

有問題繼續文章后面留言,再次感謝細心的讀者指出文章內的錯誤。

一、前言

有時候,我們會需要用到 View.post() 方法,來將一個 Runnable 發送到主線程去執行。這一切,看似很美好,它最終會通過一個 Handler.post() 方法去執行,又避免我們重新定義一個 Handler 對象。

但是,在 Android 7.0(Api level 24) 上,View.post() 將不再那么靠譜了,你 post() 出去的 Runnable ,可能永遠也不會有機會得到執行。我們先來看看它們的細節。

二、post 在 7.0 的差異

2.1 post 方法的差異

前面提到,這個問題只出現在 Android 7.0 上。那么就先從源碼分析 Android 7.0 到底對 View.post() 做了什么改動。

用 Diff 看一下它們的差異,左邊是 Api Level 24(以下簡稱 Api24) 的代碼,右邊是 Api level 23-(以下簡稱 Api23) 的代碼。

很明顯的可以看出來,它們只有在 mAttachInfo 為 null 的時候,執行的邏輯才會有差異。

Api24 中,會調用 getRunQueue().post(action),而 Api23 會調用 ViewRootImpl.getRunQueue().post(action) 方法,他們的差異就在這里。

2.2 Api23 post 的細節

先簡單理解一下,ViewRootImpl 是什么。

ViewRootImpl 可以理解是一個 Activity 的 ViewTree 的根節點的實例。每個 ViewRootImpl 就是用來管理 DecorView 和 ViewTree。

ViewRootImpl 中,用來承載 Runnable 的隊列是 sRunQueues ,它一個靜態的變量,也就是說在 App 的生命周期內,ViewRootImpl 中的這個消息隊列都是同一個。

再來看看前面提到的 ViewRootImpl.getRunQueue().post() 到底干了什么?

post() 方法只是單純的將它包裝成一個 HandlerAction 對象,然后放入 mActions 這個 ArrayList 中。繼續追查下去就需要知道 mActions 中添加的 HandlerAction 在何時被消費掉了。

消費 HandlerAction 的地方,是 executeActions() 方法。

它最終,還是調用的 handler.postDelayed() ,這沒什么好說的,關鍵點在于 executeAction() 方法,是在什么時候被調用的。

executeAction() 是被 TraversalRunnable 調用 doTraversa() ,在doTraversa() 方法中,進行調用的。而 TraversalRunnable 又是通過 Choreographer.postCallBack() 去循環調用的。這個 Choreographer 通過 doScheduleCallback() 發送一個 MSG_DO_SCHEDULE_CALLBACK 類型的消息循環調用,間隔就是一個 VSync 的間隔。

關于 Choreographer ,不是本文的重點,有興趣可以單獨了解一下。

而在 Api23 以下,executeAction() 是會被循環調用,基本上其內的 mActions 中,只要有未執行的 Runnable 立刻就會被消費掉。

所以在 Api23 以下的設備上,無論如何 View.post() 基本上是靠譜的,post 出去的 Runnable 都會有機會執行到。

2.3 Api24 的細節

再來看看在 Api24 中的實現細節,在 Api24 中,調用的是 getRunQueue().post() 方法,它操作的是一個 HandlerActionQueue 對象。

內部的結構其實和 Api23 很像,也是維護了一個 HandlerAction 的數組 mActions 。

最終消費 mActions 的地方,依然是一個 executeActions() 方法。

回到根本的問題,executeActions() 方法在什么時機會被調用到,繼續追查可以看到它在 View.dispatchAttachedToWindow() 方法中,會被調用。

既然,executeActions() 方法,在 Api24 及以上,只會在 dispatchAttachedToWindow() 的方法中,才有機會被調用到,而 View.dispatchAttachedToWindow() 方法,只有在這個 View 通過 addView() 方法,或者原本寫在頁面布局的 xml 中(實際上也是調用的 addView()),加入到一個 ViewGroup 的時候,才會被調用到。

這就導致,如果你只是通過 new 或者使用 LayoutInflater 創建了一個 View ,而沒有將它通過 addView() 加入到 布局視圖中去,你通過這個 View.post() 出去的 Runnable ,將永遠不會被執行到。 這也就是到了 Api24 下,View.post() 表現的現象不一致的緣故。

三、舉個例子說明問題

既然只是復現這個問題,秉承最小改動原則,構造一個最簡單的場景,單獨 new 一個 View 出來,然后通過它去調用 post() 方法,看看執行的結果。

可以看到,這里直接 new 了一個 View,然后 post 出去了一個 Runnable ,間隔 10s 之后,將這個 View 加入到根布局中。

看看在 Api 23 下的執行效果:

可以看到,在 Api 23一下,這里是 Api19,新 new 出來的 View 對象,post 出去的 Runnable ,會立即得到執行,不需要等待 addView() 的執行。

再來看看在 Api24 下的執行效果:

從執行時間上可以看出來,post 出去的 Runnable ,并不是立即被執行了,而是等到了 addView() 的調用之后,才被執行的,這個中間正好被間隔了 10s。

據說這個問題,在 Android 8.0 上又被修改回去了,專門找了一款 8.0 的設備試試運行結果,如下圖:

25 是 Android 8.0 的預覽版,這里可以看到,依然是和在 7.0 上的表現一樣,會等到最終 addView() 的時候再執行,正式版不知道會不會有所改動,這個還有待驗證。

基本上確定,受到影響的是 Android Api 24+,但是依然是開發者需要注意的,畢竟發布出去的 App ,具體運行在什么設備上,這就不是我們能決定的了。

四、小結

View.post() 方法,在不同版本的差異,根本原因還是在于 Api23 和 Api24 中,executeActions() 方法的調用時機不同,導致 View 在沒有 mAttachInfo 對象的時候,表現不一樣了。

所以我們在使用的過程中需要慎用,區分出實際使用的場景,一般規范自己的代碼即可:

動態創建的 View ,如果視條件去決定是否加入到根布局中,則不要使用它來調用 post() 方法。

盡量避免使用 View.post() 方法,可以直接使用 Handler.post() 方法來替代。

【本文為51CTO專欄作者“張旸”的原創稿件,轉載請通過微信公眾號聯系作者獲取授權】

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2024-01-01 08:25:53

ViewSurface框架

2020-09-28 11:14:57

線程數據語言

2023-12-12 08:41:01

2014-08-04 09:30:43

170

2024-09-18 07:00:00

消息隊列中間件消息隊列

2021-10-14 06:52:47

算法校驗碼結構

2022-09-29 15:32:58

云計算計算模式

2011-12-26 14:11:47

三星Android

2024-05-28 09:12:10

2024-04-07 00:00:00

ESlint命令變量

2019-12-12 09:23:29

Hello World操作系統函數庫

2022-03-10 08:25:27

JavaScrip變量作用域

2023-12-20 08:23:53

NIO組件非阻塞

2024-04-30 09:02:48

2023-04-26 10:21:04

2014-05-30 10:23:15

樂跑手環智能手環運動手環

2021-10-28 16:19:37

物聯網人工智能IoT

2020-10-08 18:58:46

條件變量開發線程

2024-06-20 08:06:30

2024-12-04 08:40:19

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品视频一区二区三区 | 日韩影院在线 | 国产精品99视频 | 一区二区三区四区在线视频 | 91精品久久久久久久久久入口 | 超级碰在线 | 国产高清免费 | 国产精品久久久久一区二区三区 | 亚洲网在线 | 免费永久av | av日韩在线播放 | 免费在线黄 | 久久久久久国模大尺度人体 | 天天综合成人网 | 亚洲综合区 | 亚洲成av片人久久久 | 久久精品一级 | 国产精品一区二区在线 | 午夜视频免费在线观看 | 九九热久久免费视频 | av香蕉 | 精品国产一区二区三区久久 | 五月天国产视频 | 久久精品手机视频 | 久久久久国产 | 高清色| 国产97碰免费视频 | 欧美日韩网站 | 国产欧美精品在线观看 | 波多野结衣一区二区三区 | 国产羞羞视频在线观看 | 羞羞视频网站免费看 | 在线观看视频亚洲 | 国产电影一区二区三区爱妃记 | 少妇无套高潮一二三区 | 91网站视频在线观看 | 中文字幕在线一区二区三区 | 久久国产精品偷 | 久久久精 | 欧美成人精品一区二区男人看 | 日韩视频一区 |