天天看點

Android異步回調中的UI同步性問題

android程式編碼過程中,回調無處不在。從最常見的activity生命周期回調開始,到broadcastreceiver、service以及sqlite等。activity、broadcastreceiver和service這些基本元件的回調路徑和過程也就是通常意義上所謂的“生命周期”。同時,在處理具體的業務邏輯時,常常設計到不同線程之間的通信,如下載下傳圖檔完成後通知 ui線程更新ui,凡此類場景,無論使用哪一種具體的線程間通信方式(handler/message、handler/post、基于接口的回調、基于多對多的觀察者模式如eventbus等),其本質上都是基于“回調”。在實際編碼過程中,凡涉及到不同線程之間的通信,本質上更是屬于“異步回調”。當需要在“異步回調”中修改ui時,此時需要特别注意ui同步性問題。

為了便于問題的闡述,在此先對“android異步回調ui同步性問題”進行如下界定:當異步回調執行時(稱之為“異步回調執行點”),目前ui界面上的元素與最初生成此異步回調的調用器開始執行時(稱之為“異步回調生成點”)的ui元素已經存在不一緻,不一緻不僅包括ui元素可能的界面變化、可能的内容變化,也包括“異步回調執行點”和“異步回調生成點”時的ui元素中的某一特性的表征量(如某一具有表征目前ui元素的字段值)相關,即使ui元素界面和内容都尚未發生變化。

編碼過程中,“android異步回調ui同步性問題”經常存在,有時候稍不注意會産生一些看起來難以了解的bug,并由于異步特性的存在,此類bug還具有一定的随機性。有時候由于一些需求的複雜性,此類bug隐蔽性很強,也容易被忽略。至少到目前為止,在實際開發中,本人遇到此類問題已有數個。

純文字的描述可能不太好了解,下面以一個很常用的android-universal-image-loader為例,簡單舉例一個潛在存在的“android異步回調ui同步性問題”。

listview item view中有imageview,通過android-universal-image-loader去加載顯示,圖檔加載完成後需要做一些邏輯處理(如隐藏圖檔加載進度條等..),通常代碼如下:

初看上去,代碼邏輯好像也沒什麼問題,網上大部分人也是這麼寫的。當較慢滑動listview時,或在平時正常使用時,也沒有什麼問題。但是此處的代碼邏輯真的嚴密嗎?

listview的getview複用特性,大家也都熟知。對于之前遇到的“圖檔錯位/先顯示之前的圖檔後再被正确的圖檔覆寫掉”,此類現象也都知道如何解決(在getview邏輯開始處理處将imageview設定成最先的預設圖檔,其他ui元素類似處理),基本上也不會再有“圖檔錯位/先顯示之前的圖檔後再被正确的圖檔覆寫掉”這類現象了。實際上,當網速條件一般,且loadimage大緻與上述代碼所示,在listview中快速滑動清單,幾屏後,不出意外,會發現“圖檔錯位/先顯示之前的圖檔後再被正确的圖檔覆寫掉”此問題依然存在。

此時問題出現的原因不在于getview本身,因為getview邏輯開始時已經将imageview重置為預設圖檔,而在于“android異步回調ui同步性問題”。由于viewholder的不斷複用,網速一般時快速滑動幾屏後,onloadingcomplete的異步回調執行時與目前ui元素已經存在不一緻,簡單點了解,imageview被複用了imageview position 0,imageview position 11, imageview position

21,此時滑動停止,onloadingcomplete的異步回調執行時imageview已經是最後一次的imageview position 21,而onloadingcomplete的異步回調可能被執行數次(imageview position 0,imageview position 11, imageview position 21,且順序還取決于異步中的具體處理和網絡環境等),于是問題發生了。

解決方案:

抓住”ui元素中的某一特性的表征量“,在異步回調中通過比較“異步回調生成點”和“異步回調執行點”此特征變量的值直接作出邏輯上的處理。

總之,凡此類“android異步回調ui同步性問題”,最好都通過比較“異步回調生成點”和“異步回調執行點”特征變量的值去針對性的做邏輯處理,以免出現不必要的bug,是非常必要且有效的手段。

轉自:http://www.cnblogs.com/lwbqqyumidi/p/4110377.html

繼續閱讀