文章概述:
1.前提
2.什么是item復(fù)用
3.為什么會(huì)錯(cuò)亂
4.解決錯(cuò)亂
前提
最近幾日一直在忙于面試,各種奇奇怪怪的問題也讓我明白了自己的一些不足。沒辦法,不懂就要學(xué)習(xí),這也算是提高自己的一種方式吧。
昨天面試一家直播app公司的時(shí)候面試官問了我這樣一個(gè)問題:
在一個(gè)listview里每個(gè)item中都有一個(gè)動(dòng)畫(gif)播放的view,當(dāng)我點(diǎn)擊item中的button時(shí)動(dòng)畫(gif)播放。當(dāng)有動(dòng)畫播放時(shí)滑動(dòng)listview,偶爾會(huì)發(fā)生item錯(cuò)位的事件。
問:原因是什么,如何解決?
當(dāng)我聽完這個(gè)問題后隨口便說道“這是item復(fù)用的問題,由于異步加載導(dǎo)致圖片錯(cuò)位”
對(duì)于接觸Android一段時(shí)間的同學(xué)可能都應(yīng)該知道listview優(yōu)化時(shí)會(huì)用到item復(fù)用,但是原理可能不太清楚,接下來我們就來先說一下究竟什么是“item復(fù)用”
什么是item復(fù)用
在我們平常編寫adapter時(shí)一般會(huì)重寫他的個(gè)getView()這個(gè)方法

在這段代碼中我們首先做的就是去判斷convertView是否為空,那么這個(gè)convertView是什么呢?
初始化時(shí)ListView先請(qǐng)求一個(gè)type1視圖(getView),這時(shí)的convertView在getView中是空(null)。當(dāng)item1滑動(dòng)出屏幕,并且一個(gè)新的項(xiàng)目從屏幕低端上來時(shí),ListView再請(qǐng)求一個(gè)type1視圖。這個(gè)時(shí)候convertView此時(shí)不是空值了,它的值是item1。你只需設(shè)定新的數(shù)據(jù)然后返回convertView,不必重新創(chuàng)建一個(gè)視圖。如下圖所示:

為什么會(huì)錯(cuò)亂
明白了item復(fù)用的原理后我們就來探究一下錯(cuò)亂的原因吧,通過查看源碼我們可以得知原來AbListView中獲取getView()和滑動(dòng)操作是異步進(jìn)行的,其中滑動(dòng)操作在一個(gè)FlingRunnable的支線程中運(yùn)行,所以這就導(dǎo)致了在ListView在滑動(dòng)時(shí)可能已經(jīng)滑動(dòng)到了第十行,但可能第二行的數(shù)據(jù)這時(shí)就被直接使用了,這就是導(dǎo)致數(shù)據(jù)加載錯(cuò)亂的根本原因。
源碼的注解如圖所示:

由于滑動(dòng)和加載是異步進(jìn)行的,這樣就會(huì)出現(xiàn)一些意想不到的問題:
a. 行item圖片顯示重復(fù)
b. 行item圖片顯示錯(cuò)亂
c. 行item圖片顯示閃爍
解決錯(cuò)亂
知道了錯(cuò)亂的原因,那么解決起來應(yīng)該就很簡單了,我們可以給圖片設(shè)置tag來避免數(shù)據(jù)錯(cuò)亂

當(dāng)然還有其他的解決辦法比如使用第三方的圖片加載庫來加載圖片一樣可以解決。