1. 程式人生 > >關於RecyclerView非同步載入圖片錯位的小總結

關於RecyclerView非同步載入圖片錯位的小總結

1.總體思路

很明顯這個問題在如今的Android開發中已經算不上問題,因為其產生原因,解決方法已經被討論的非常成熟。這篇部落格主要是自己在遇到問題到解決問題的的過程中,總結的一些可以幫助自己理清思路的小套路。

這裡還是簡單說明下問題原因及大致思路。RecyclerView,包括之前用的ListView都存在這個問題。因為有ViewHolder的重用機制,每一個item在移除屏幕後都會被重新使用以節省資源,避免滑動卡頓。而在圖片的非同步載入過程中,從發出網路請求到完全下載並載入成Bitmap的圖片需要花費很長時間,而這時候很有可能原先需要載入圖片的item已經劃出介面並被重用了。而原先下載的圖片在被載入進ImageView的時候沒有判斷當前的ImageView是不是原先那個要求載入的,故可能圖片被載入到被重用的item上,就產生了圖片錯位的問題。解決思路也很簡單,就是在下載完圖片,準備給ImageView裝上的時候檢查一下這個ImageView
還是不是原來那個。

關鍵虛擬碼如下:

//給ImageView打上Tag作為特有標記
imageView.setTag(tag);

//下載圖片
loadImage();

//根據tag判斷是不是需要設定給ImageView
if(tag == iamgeView.getTag()) {
    imageView.setBitmapImage(iamge);
}

2.注意細節

實現起來難度不大,網上也都解釋的很詳細了,這裡就不說怎麼做了。就是一些細節和小技巧可能會需要注意一下。

  1. 給ImageView打的Tag可以就是圖片的url,也可以加上position等位置引數
  2. 在載入圖片的時候,一定要注意新增tag和判斷tag的時機,從日誌分析執行的先後順序,理清邏輯。我就多次在這裡踩坑了。比如圖片已經下載完成了,但是重用的ImageView還沒有覆蓋新的tag。
  3. 我的ImageView是放在一個子佈局 GridLayout裡面,數量從0到9。在圖片數量為0的時候,注意搞清楚後臺返還的urls陣列是null還是size()==0。
  4. 每次bindViewHolder時,GridLayout注意要removeAllViews()。這樣比較簡單粗暴,要優化還可以僅僅remove掉多餘view,然後注意把剩下的view設定一個預設圖片。
  5. 在沒有載入到圖片之前,設定預設的圖片資源(我感覺對我用處不大,不過網上都建議這樣做)
  6. 圖片的大小:getWidth()這個方法所依賴的測量值是非同步的,所以就有可能得到不準確的值,造成圖片大小設定不恰當。

3.時間及事件梳理

因為自己在這裡踩坑太多且花了很長時間才爬出來,所以著重記錄一下。
開始->當前item1給ImageView打tag
->當前item1發起網路請求
->非同步處理網路請求
->當前item1滑出螢幕
->劃出螢幕的item重用並滑進螢幕命名為item2
->item2重新給ImageView打上tag
->item1的圖片下載完成,因為重用的原因,圖片將要載入給item2
->用原先傳入的item1設定的tag和新覆蓋的tag比較,發現不相同
->不給當前item2設定圖片,避免了圖片錯位

4.程式碼

想了下,我寫的太多關於自己佈局和業務的東西,不適合單獨拿出來說明問題,就不貼了。以後有空了單獨寫一個出來用作示例。