1. 程式人生 > >ListView中子view複用機制的實現原理以及圖片錯位的解決方案

ListView中子view複用機制的實現原理以及圖片錯位的解決方案

ConvertView複用原理圖:藉助於RecycleBin(回收站)實現複用;

RecycleBin的作用:對子View進行回收利用。


移出螢幕的ImageView控制元件會進入到RecycleBin當中,而新進入螢幕的元素則會從RecycleBin中獲取ImageView控制元件。

圖片錯位原因:
如果我們只是簡單顯示list中資料,而沒用convertview的複用機制和非同步操作,就不會產生圖片錯位;重用convertview但沒用非同步,也不會有錯位現象。

RecycleBin工作原理解釋:

ListView會把那些移出螢幕的子view放入到RecycleBin中存起來,就像把暫時無用的資源放到回收站一樣。

當 ListView的底部需要顯示新的View的時候,會從RecycleBin中取出一個子View,將其作為convertView引數傳遞給 Adapter的getView方法,從而達到View複用的目的,這樣就不必在Adapter的getView方法中執行LayoutInflater.inflate()方法了。

RecycleBin中有兩個重要的View陣列,分別是 mActiveViews和mScrapViews。這兩個陣列中所儲存的View都是用來複用的,只不過mActiveViews中儲存的是 OnScreen的View,這些View很有可能被直接複用;而mScrapViews中儲存的是OffScreen的View,這些View主要是用 來間接複用的。


產生錯位的原因:ConvertView複用+非同步同時使用時產生。

每當有新的元素進入介面時就會回撥getView()方法,而在getView()方法中會開啟非同步請 求從網路上獲取圖片,注意網路操作都是比較耗時的,也就是說當我們快速滑動ListView的時候就很有可能出現這樣一種情況,某一個位置上的元素進入屏 幕後開始從網路上請求圖片,但是還沒等圖片下載完成,它就又被移出了螢幕。這種情況下會產生什麼樣的現象呢?根據ListView的工作原理,被移出螢幕 的控制元件將會很快被新進入螢幕的元素重新利用起來,而如果在這個時候剛好前面發起的圖片請求有了響應,就會將剛才位置上的圖片顯示到當前位置上,因為雖然它們位置不同,但都是共用的同一個ImageView例項,這樣就出現了圖片亂序的情況。

但是還沒完,新進入螢幕的元素它也會發起一條網路請求來獲取當前位置的圖片,等到圖片下載完的時候會設定到同樣的ImageView上面,因此就會出現先顯示一張圖片,然後又變成了另外一張圖片的情況,那麼剛才我們看到的圖片會自動變來變去的情況也就得到了解釋。

解決方法:對imageview設定tag,並預設一張圖片。
向下滑動後,item6顯示,item0隱藏。但由於item0是第一次進來就顯示,所以一般情況下,item0都會比item6先下載完,但由於此時可 見的item6的tag,和隱藏了的item0的url不匹配,所以就算item0的圖片下載完也不會顯示到item6中,因為tag標識的永遠是可見圖 片中的url。

關鍵程式碼:

// 給 ImageView 設定一個 tag

holder.img.setTag(imgUrl);

// 預設一個圖片

holder.img.setImageResource(R.drawable.ic_launcher);

// 通過 tag 來防止圖片錯位

if (imageView.getTag()!= null && imageView.getTag().equals(imageUrl)) {

    imageView.setImageBitmap(result);

}

或者使用findViewWithTag()方法。