實現高效能微信朋友圈

KCrason發表於2018-05-03

眾所周知,微信朋友圈的列表一直以來被眾多研究效能問題的朋友拿來作為模範,對於其實現方式,一直以來有點難以望其項背的感覺。只能默默的感嘆微信的開發者是真的牛逼。經過一段時間的研究,現在我將帶領大家以全新的認知對微信朋友圈的結構進行分析,並通過自己的方式加以實現。 先上圖:

20180503_222857.gif

GIF看著有點卡,可以下載apk自行體驗,流暢度和微信幾乎無差別:app-debug.apk

原始碼地址:HighPerformanceFriendsCircle

我們都知道,在Android中,對於列表的而言,要避免其卡頓,可以從以下幾個角度進行優化。

1、減少佈局層級,避免過多的Item View的無用佈局巢狀。 2、對於有圖片的列表,要在滑動時對圖片加以控制,即滑動時不載入圖片,停止滑動之後再載入圖片。 3、應當避免在Adapter的填充資料時做過多的計算,或者巢狀過多的邏輯判斷。對於複雜的計算結果應當在Adapter填充資料之前計算完成。

以上這些都是針對一個普通的Adapter所基本的一些優化,而對於微信朋友圈這種複雜列表,除了以上幾種之外,還需要對其進行其他方面的優化。例如包括減少View的重複建立,構建快取View,以及減少佈局的onMeasure和onLayout次數。這些都尤為重要。下面我們先簡單分析一些微信的列表每一項的檢視結構,通過分析微信,我們可以參悟到一些自己的解決思路。

首先我們通過Android Device Monitor檢視分析器來分析微信朋友圈的每一個Item的檢視結構。

實現高效能微信朋友圈
從圖中我們可以知道,它的Item最外部是一個FramLayout,裡面的內容都是一些常見的View,關鍵的地方在於評論列表的構建,我們知道,微信的評論是直接在列表內展示的,在這裡我們發現它的評論列表其實就是一個用一個LinearLayout進行包裹的。而由於每條動態評論的不確定性,我們需要在adapter中不斷的建立評論View和移除多餘的View,就這涉及到效能問題,那麼微信到底是如何在一個Item中展示多條評論又不出現明顯的卡頓現象呢?

在ViewGroup中,有個一方法可能一直被大家所忽略,它就是addViewInLayout(),由於它是protected宣告的,所以外部的ViewGroup的子類無法直接呼叫,而要使用addViewInLayout(),必須繼承ViewGroup或ViewGroup的子類並重寫該方法。那麼addViewInLayout()方法究竟有何用呢?它和我們常用的addView()又有什麼區別呢?

我們先來看官方對addViewInLayout()的解釋:

實現高效能微信朋友圈

簡單翻譯:在佈局中新增檢視。 如果在onLayout()方法中,您需要新增更多檢視(例如列表檢視),這非常有用。 如果索引是負數,則意味著將其放在列表的末尾。

這似乎沒什麼特殊的,但是它真正的有用的地方在於該方法中的preventRequestLayout引數,這是一個boolean型別的值,但是它確實及其有用的。如果為true,在新增View時他將不會觸發子物件的佈局請求。也就是說新增View時不會觸發onMeasure和onLayout操作。官方api解釋圖:

H

通過對addViewInLayout()的分析,我想你大概明白了,既然動態新增View的時候可以不用觸發onMeasure()和onLayout(),那將大量的節約adapter的重新整理速度。上面我們有提到過,對adapter的效能要點中,減少adapter Item的onMeasure和onLayout尤為重要(因為事實上View的顯示onMeasure和onLayout需要耗費大量的時間)。

同樣的,在移除View時,我們可以使用removeViewInLayout(),它有和addViewInLayout()一樣的效果。因此,通過這個辦法,我們解決了評論列表的動態變化更新的效能問題。

而九宮格圖片的展示只需要自定義ViewGroup即可實現,其內部依然是對ImageView的新增和移除,同樣的我們可以使用該方法addViewInLayout()和removeViewInLayout()來減少onMeasure()和onLayout()的次數以節省效能開支。

其他方面的優化則是儘管在資料Bean中完成對各種資料變換的操作,包括複雜的計算,比如將String轉換成需要的SpannableStringBuilder等。

最後就是除了要減少onMeasure()和onLayout()的次數之後,我們也需要減少View的建立。減少View的建立我們可以使用一個弱引用的快取陣列和實現View物件的快取,這裡要感謝razerdp提供的思路。

具體的一些其他邏輯,程式碼中自行研究吧,後續可能還會繼續更新該專案,包括表情的匹配,電話號碼的匹配等,看自己時間情況。歡迎大家start!

特別說明:

昨天有一位網友提出了一個問題,後面經過分析,發現在adapter中使用addViewInLayout()和addView()去新增一個或多個View無異,也就是說在adapter中構建評論資料時使用addViewInLayout()並不會減少onMeasure()和onLayout()的次數,原因後續再單獨出一篇文章進行說明,這裡感謝@Caij的指正!

相關文章