關於優化RecyclerView scrolling

目前專案UI有一個WebView即時地顯示串流的影像,而此同時在右半邊有用來瀏覽影音資源的RecyclerView,由於是Embedd Android,在可用資源(RAM, CPU)會比較受限。

這次遇到的問題:當WebView即時播放的時候,在瀏覽影音的RecyclerView在手指快速往下滑動時,會造成WebView的聲音有所停頓。雖然想要針對WebView的項目做優化,但是Chromium頗複雜,在時間有限的情況下,先看看RecyclerView該怎麼優化吧!

問題的思路有幾個:主要的方向還是資源的優化,避免在同一時間要求過多的資源&減少RecyclerView相關機制花費的時間。

從網路上尋找到單純關於RecyclerView優化的topic

  1. 減少Item Layout的複雜度:我們的Layout原本使用了三層的LinearLayout(見下圖),而後改成了ConstraintLayout

2. RecyclerView.setHasFixedSize(true):讓RecyclerView 減少requestLayout 來重新量測寬高 [1]

3. RecyclerView.setItemCacheSize(_size):當Item滑離當前Window,會額外存起來的size數量,一旦超過會重新呼叫onBindViewHolder [2]

4. RecycelrView.setDrawingCacheEnabled(true) & RecyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH):減少繪製的時間 [3]

5. 把View.setOnClickListener放在onCreateViewHolder而非onBindViewHolder :由於onBindViewHolder會因為複用多次被呼叫,盡可能讓onBindViewHolder越簡單越好


我們都知道,在RecyclerView Item從onCreateViewHolder開始繪製layout並產生ViewHolder,接著在onBindViewHolder拿資料,在我們的服務上面,要將Item的資料完整取得需要:

  1. 透過Rest API + Item ID拿取Item的meta data
  2. 在meta data裡面有Item ID的thumbnail url,這時需要額外再行載圖

Thumbnail的加載可以使用第三方的工具如Picasso, Glide, Fresco等,原本使用的是Picasso,但是看了一下[報告] (在沒有動畫的情況下)

看來Picasso還有很多進步空間

恩,果斷換成Glide,然後搜尋相關的優化,找到了這篇

重點是最後一項。快速滑動RecyclerView的時候,不考慮Cache情況下,會先依照Item數量持續呼叫 onCreateViewHolder -> onBindViewHolder。由於onBindViewHolder會持續產生http request, 在拿取metadata以後又需要呼叫載圖,而Glide可以依照情況呼叫 pauseRequests()/ resumeRequest()

其中IDLE指的是沒有滑動,DRAGGING是手指還在拖動未離開螢幕,SETTLING是手指已經離開螢幕而View持續滑動中的狀態。

以上是這次的分享。