ListView的View回收引起的checkbox狀態(tài)改變監(jiān)聽等問題解決方案
還是這個(gè)問題,講一個(gè)我遇到的因?yàn)閮尚写a位置相反引起的問題。
我的ListView中每行View包含一個(gè)ImageView、TextView、CheckBox。當(dāng)ListView中有一個(gè)或一個(gè)一行CheckBox被選中就讓ListView上面的Button顯示,否則就隱藏。因此,需要對(duì)每行View中的CheckBox設(shè)置監(jiān)聽。我使用CheckBox中的OnCheckedChangeListener監(jiān)聽器,當(dāng)CheckBox的狀態(tài)發(fā)生改變的時(shí)候就會(huì)觸發(fā)這個(gè)監(jiān)聽器。先看下我自定義給ListView的Adapter的getView方法中的一些關(guān)鍵代碼:
這是getView方法中使用到的內(nèi)部類:
static class ViewHolder {
public ImageView imageView;
public TextView textView;
public CheckBox checkBox;
}
這是getView方法中利用ListView回收機(jī)制循環(huán)利用View的代碼:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.searchitem, null);
viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) convertView
.findViewById(R.id.searchitemimage);
viewHolder.textView = (TextView) convertView
.findViewById(R.id.searchitemtext);
viewHolder.checkBox = (CheckBox) convertView
.findViewById(R.id.searchitemcheckbox);
convertView.setTag(viewHolder);
} else {
// Log.i(CodeUtils.SEARCHTAG, "view is reuse");
viewHolder = (ViewHolder) convertView.getTag();
}
接下來是對(duì)其中checkbox設(shè)置顯示狀態(tài)和監(jiān)聽器的代碼:
viewHolder.checkBox
.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(
position, state));
viewHolder.checkBox.setChecked(state[position]);
之前說過了,因?yàn)長(zhǎng)istView的回收,需要使用一個(gè)數(shù)組或list來記錄每項(xiàng)數(shù)據(jù)中checkbox的狀態(tài)。這里,state是與ListView列表等長(zhǎng)的boolean數(shù)組,用于記錄每個(gè)position(也就是每個(gè)列表項(xiàng)數(shù)據(jù)的id)標(biāo)識(shí)的數(shù)據(jù)上checkbox應(yīng)該顯示的狀態(tài),初始的狀態(tài)都是false。構(gòu)造checkbox監(jiān)聽器的時(shí)候需要傳遞當(dāng)前View的position,以及整個(gè)列表checkbox的狀態(tài)數(shù)組state。以下是checkBox狀態(tài)改變監(jiān)聽器的代碼:
public class SearchItemOnCheckedChangeListener implements
OnCheckedChangeListener {
private int id;
private Boolean[] state;
public SearchItemOnCheckedChangeListener(int id, Boolean[] state) {
this.id = id;
this.state = state;
}
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
state[id] = isChecked;
if (isChecked) {
checkedCount++;
}else{
checkedCount--;
}
if (checkCoutn>0) {
searchButton.setVisibility(Button.INVISIBLE);
} else {
searchButton.setVisibility(Button.VISIBLE);
}
}
}
}
這里面checkedCount初始值為0的整型,用于記錄被選中多選框的數(shù)量。searchButton是根據(jù)checkbox而決定顯示還是隱藏的按鈕。
以上整個(gè)邏輯功能的實(shí)現(xiàn)代碼。開頭說了,這是一個(gè)我因?yàn)長(zhǎng)istView的回收機(jī)制和兩行代碼位置相反引起的問題。兩行代碼的位置相反將導(dǎo)致完全不同的結(jié)果,所指的就是設(shè)置checkbox監(jiān)聽器和狀態(tài)的兩行代碼,起初我的順序?yàn)椋?
viewHolder.checkBox.setChecked(state[position]);
viewHolder.checkBox.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(position, state));
這樣的順序出現(xiàn)的問題是,當(dāng)我拉動(dòng)列表后,因?yàn)槔瓌?dòng)被隱藏的列表項(xiàng)狀態(tài)將被更改為false。這很不可思議,因?yàn)槲乙呀?jīng)分離了一個(gè)狀態(tài)數(shù)組來記錄每個(gè)checkbox的狀態(tài),想來想去只有一個(gè)可能,就是狀態(tài)數(shù)組中的值改變了,而改變狀態(tài)數(shù)組的值位置就在于OnCheckedChangeListener中。Debug了幾個(gè)小時(shí),才想通了問題就在于這兩行代碼為位置順序。
起因還是得講到ListView的回收機(jī)制。假如我的ListView最多只能顯示10個(gè)View,那么起初就會(huì)調(diào)用十次getView構(gòu)造十個(gè)全新的View(包括對(duì)其中的checkbox設(shè)置監(jiān)聽器)。當(dāng)我將列表往下拉出現(xiàn)第11個(gè)列表項(xiàng)的時(shí)候,頂部第一個(gè)列表項(xiàng)被隱藏,同樣會(huì)再調(diào)用一次getView,不過此時(shí)getView的參數(shù)將返回剛剛被隱藏的第一個(gè)列表項(xiàng)的View,并對(duì)這個(gè)View更改數(shù)據(jù)作為即將出現(xiàn)的第11個(gè)View。問題就出在這里,我把checkbox.setChecked()方法調(diào)用放在了設(shè)置監(jiān)聽器前面,此時(shí)因?yàn)楦牧薱heckbox的狀態(tài),勢(shì)必引起觸發(fā)狀態(tài)更改的監(jiān)聽器。注意!由于第11個(gè)View是用被隱藏的第1個(gè)View回收來的,雖然還沒有執(zhí)行下一行設(shè)置監(jiān)聽器的代碼,但實(shí)際上它已經(jīng)擁有了一個(gè)狀態(tài)監(jiān)聽器,這個(gè)監(jiān)聽器是這個(gè)View還是作為第一個(gè)View時(shí)設(shè)置。那個(gè)時(shí)候的監(jiān)聽器設(shè)置更改的第一項(xiàng)的數(shù)據(jù),而不是第11項(xiàng)數(shù)據(jù)。因此,理所當(dāng)然不能正確更改第11項(xiàng)數(shù)據(jù),反而更改了無辜的第1項(xiàng)數(shù)據(jù)。如果我把兩行代碼順序反過來,先更改監(jiān)聽器,再設(shè)置狀態(tài),引發(fā)的監(jiān)聽器自然也就是新的監(jiān)聽器,邏輯也就對(duì)了。
相關(guān)文章
Android實(shí)現(xiàn)屏幕各尺寸的獲取的示例
本篇文章主要介紹了Android實(shí)現(xiàn)屏幕各尺寸的獲取的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09Android使用Messenger實(shí)現(xiàn)service與activity交互
這篇文章主要介紹了android使用Messenger實(shí)現(xiàn)service與activity交互的相關(guān)資料,需要的朋友可以參考下2016-06-06關(guān)于Android WebView的loadData方法的注意事項(xiàng)分析
本篇文章是對(duì)Android中WebView的loadData方法的注意事項(xiàng)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06分享10個(gè)很棒的學(xué)習(xí)Android開發(fā)的網(wǎng)站
我推薦的網(wǎng)站,都是我在學(xué)習(xí)Android 開發(fā)過程中發(fā)現(xiàn)的好網(wǎng)站,給初學(xué)者一些建議,少走一些彎路2015-03-03Android性能調(diào)優(yōu)利器StrictMode應(yīng)用分析
StrictMode意思為嚴(yán)格模式,是用來檢測(cè)程序中違例情況的開發(fā)者工具。最常用的場(chǎng)景就是檢測(cè)主線程中本地磁盤和網(wǎng)絡(luò)讀寫等耗時(shí)的操作。這篇文章給大家介紹Android性能調(diào)優(yōu)利器StrictMode應(yīng)用分析,感興趣的朋友一起看看吧2018-01-01限時(shí)搶購(gòu)秒殺系統(tǒng)架構(gòu)分析與實(shí)戰(zhàn)
這篇文章主要介紹了限時(shí)搶購(gòu)秒殺系統(tǒng)架構(gòu)分析與實(shí)戰(zhàn) 的相關(guān)資料,需要的朋友可以參考下2016-01-01Android查看電池電量的方法(基于BroadcastReceiver)
這篇文章主要介紹了Android查看電池電量的方法,結(jié)合實(shí)例分析了Android使用BroadcastReceiver實(shí)現(xiàn)針對(duì)電池電量的查詢技巧,需要的朋友可以參考下2016-01-01Android 使用 Path 實(shí)現(xiàn)搜索動(dòng)態(tài)加載動(dòng)畫效果
這篇文章主要介紹了Android 使用 Path 實(shí)現(xiàn)搜索動(dòng)態(tài)加載動(dòng)畫效果,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下2018-08-08Android UniversalVideoView實(shí)現(xiàn)視頻播放器
這篇文章主要為大家詳細(xì)介紹了Android UniversalVideoView實(shí)現(xiàn)視頻播放器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04