標籤:
原文:Android ListView複雜列表最佳化實踐
很多社交App都不免會涉及到複雜的列表元素實現,一個列表上面可能大量的圖片,不定長的評論列表,給手機端的程式員帶來了不少的挑戰。本文就是在實現複雜的列表滑動的情況下,利用已知的最佳化方法指導下的一次最佳化實踐,旨在提升ListView的滑動流暢度,為使用者帶來良好的體驗。
1:設計稿:
這是列表中可能出現的ItemView,有兩種,但是又有許多相同的地方,比如一樣有點贊的圖片,評論等...其中,評論和點贊的數量是可變的。
2:使用一般布局帶來的問題?
頭像表格:如果使用內建的布局LinearLayout和ImageView來完成,會導致布局比較深,而且大量的addView操作會導致列表滑動的時候卡頓。
評論列表:和頭像表格一樣,由於Item的數量是會變化的,會帶上和頭像表格同樣的問題。
大量圖片載入: 不難看出圖片的數量是可觀的,由於每次請求回來的內容可能有很多條,如果資料一回來就請求裡面帶的全部圖片連結,即使使用了線程池,也會佔用cpu比較長的一段時間,因此也會帶來介面的不流暢問題。
3:指導最佳化思路:
(1): ViewHolder模式, 重用View和減少Child View尋找時間,相信大家對這個都不陌生。
(2): 儘可能減少布局層次
(3): 只重新整理變化的部分View
(4): 避免調用addView這樣的方法
(5): 只載入當前視圖需要的圖片,並且在滑動列表的時候停止背景載入線程,為UI線程空出cpu資源,在停止的時候再請求。
(6): 首次載入圖片就處理(圓角/縮放等)並緩衝在本地
4:實踐過程: 4.1:布局和View部分:
把【頭像表格】和【評論列表】作為一個整體的自訂View來實現,右邊的卡片結構基本一個RelativeLayout就可以實現了,這樣整個Item就基本可以控制在3~4個層次深度上面。
【頭像表格】實現注意點:
1):一開始應該先用預設頭像填充,之後再圖片返回的時候不要粗魯地使用invalidate(),而是使用invalidate(Rect rect),進行局部重新整理,響應點擊事件更換背景時也應如此。
2):由於onMesure和onDraw的的過程是比較頻繁和代價較高的,因此要儘可能複用對象,如(Paint, Rect...)
【評論列表】實現要點:
1):除了上面提到的,這裡有個痛點就是字串的繪製,什麼時候該換行?這裡涉及到非常複雜的文文書處理,尤其是不同國家的不同文字系統,幸好,這些在Android API裡面都有了相關實現,筆者是在TextView中找到的,也就是android.text.Layout 的幾個實作類別,筆者在這裡只是使用了DynamicLayout來實現。通過這個類你可以獲得字串的高度資訊(onMeasure),行數等...而且它已經實現了draw的過程,只需調整好畫布的位置(canvas.translate),直接調用就可以了,非常方便。
【額外元素】
1):回到設計圖上,我們看到還有可能出現的股票資訊,對於這種額外元素,<ViewStub>最適合不過了...
【ListView】的資料變化:
1):對於整個Item的增加或者刪除動作,可以調用notifyDataChanged()。
2):對於Item內部的資料變化,不要粗魯地使用notifyDataChanged(), 而是改變產生變化的View。
4.2:圖片處理部分:
筆者一開始的想法是想做到:
1): 線程池,並且可以暫停所有下載線程和恢複下載
2): 雙重緩衝,本地永久緩衝和記憶體級緩衝
3): 滑動時候暫停所有下載,出讓cpu資源給UI線程。
在實現的過程中,在多線程這裡經常做的不好,經常出問題,非常幸運在github上找到了一個開源項目可以完美地解決上面的所有問題。現在我們公司的Android項目所有的圖片載入已經自豪地使用上了... 附上地址:Android-Universal-Image-Loader
5:調整之後的效果:
由於筆者沒有保留之前的介面卡頓時候的代碼,因此只能示範最後的實現效果了,不能進行前後的比較。手機是小米4,圖表是Developer選項中的Profile GPU rendering中,開啟後前後不斷滑動的結果。這裡可以看到大部分情況都能在綠線下,說明整體的體驗還是非常流暢的。
喜歡炒股的朋友也可以進一步去下載我們的應用:微財 , 即將在3.0版本可以體驗到。
Android ListView複雜列表最佳化實踐