ListView的View回收引起的checkbox狀態(tài)改變監(jiān)聽等問題解決方案
更新時間:2013年01月21日 14:37:56 作者:
之前講到了自定義Adapter傳遞給ListView時,因為ListView的View回收,需要注意當(dāng)ListView列表項中包含有帶有狀態(tài)標(biāo)識控件的問題,感興趣的朋友可以祥看本文,或許會有意外的收獲哦
之前講到了自定義Adapter傳遞給ListView時,因為ListView的View回收,需要注意當(dāng)ListView列表項中包含有帶有狀態(tài)標(biāo)識控件的問題。詳情可見之前發(fā)的帖[url=自定義Adapter實現(xiàn)ListView帶多選框等狀態(tài)控件的注意事項 http://chabaoo.cn/article/33425.htm
還是這個問題,講一個我遇到的因為兩行代碼位置相反引起的問題。
我的ListView中每行View包含一個ImageView、TextView、CheckBox。當(dāng)ListView中有一個或一個一行CheckBox被選中就讓ListView上面的Button顯示,否則就隱藏。因此,需要對每行View中的CheckBox設(shè)置監(jiān)聽。我使用CheckBox中的OnCheckedChangeListener監(jiān)聽器,當(dāng)CheckBox的狀態(tài)發(fā)生改變的時候就會觸發(fā)這個監(jiān)聽器。先看下我自定義給ListView的Adapter的getView方法中的一些關(guān)鍵代碼:
這是getView方法中使用到的內(nèi)部類:
static class ViewHolder {
public ImageView imageView;
public TextView textView;
public CheckBox checkBox;
}
這是getView方法中利用ListView回收機制循環(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();
}
接下來是對其中checkbox設(shè)置顯示狀態(tài)和監(jiān)聽器的代碼:
viewHolder.checkBox
.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(
position, state));
viewHolder.checkBox.setChecked(state[position]);
之前說過了,因為ListView的回收,需要使用一個數(shù)組或list來記錄每項數(shù)據(jù)中checkbox的狀態(tài)。這里,state是與ListView列表等長的boolean數(shù)組,用于記錄每個position(也就是每個列表項數(shù)據(jù)的id)標(biāo)識的數(shù)據(jù)上checkbox應(yīng)該顯示的狀態(tài),初始的狀態(tài)都是false。構(gòu)造checkbox監(jiān)聽器的時候需要傳遞當(dāng)前View的position,以及整個列表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而決定顯示還是隱藏的按鈕。
以上整個邏輯功能的實現(xiàn)代碼。開頭說了,這是一個我因為ListView的回收機制和兩行代碼位置相反引起的問題。兩行代碼的位置相反將導(dǎo)致完全不同的結(jié)果,所指的就是設(shè)置checkbox監(jiān)聽器和狀態(tài)的兩行代碼,起初我的順序為:
viewHolder.checkBox.setChecked(state[position]);
viewHolder.checkBox.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(position, state));
這樣的順序出現(xiàn)的問題是,當(dāng)我拉動列表后,因為拉動被隱藏的列表項狀態(tài)將被更改為false。這很不可思議,因為我已經(jīng)分離了一個狀態(tài)數(shù)組來記錄每個checkbox的狀態(tài),想來想去只有一個可能,就是狀態(tài)數(shù)組中的值改變了,而改變狀態(tài)數(shù)組的值位置就在于OnCheckedChangeListener中。Debug了幾個小時,才想通了問題就在于這兩行代碼為位置順序。
起因還是得講到ListView的回收機制。假如我的ListView最多只能顯示10個View,那么起初就會調(diào)用十次getView構(gòu)造十個全新的View(包括對其中的checkbox設(shè)置監(jiān)聽器)。當(dāng)我將列表往下拉出現(xiàn)第11個列表項的時候,頂部第一個列表項被隱藏,同樣會再調(diào)用一次getView,不過此時getView的參數(shù)將返回剛剛被隱藏的第一個列表項的View,并對這個View更改數(shù)據(jù)作為即將出現(xiàn)的第11個View。問題就出在這里,我把checkbox.setChecked()方法調(diào)用放在了設(shè)置監(jiān)聽器前面,此時因為更改了checkbox的狀態(tài),勢必引起觸發(fā)狀態(tài)更改的監(jiān)聽器。注意!由于第11個View是用被隱藏的第1個View回收來的,雖然還沒有執(zhí)行下一行設(shè)置監(jiān)聽器的代碼,但實際上它已經(jīng)擁有了一個狀態(tài)監(jiān)聽器,這個監(jiān)聽器是這個View還是作為第一個View時設(shè)置。那個時候的監(jiān)聽器設(shè)置更改的第一項的數(shù)據(jù),而不是第11項數(shù)據(jù)。因此,理所當(dāng)然不能正確更改第11項數(shù)據(jù),反而更改了無辜的第1項數(shù)據(jù)。如果我把兩行代碼順序反過來,先更改監(jiān)聽器,再設(shè)置狀態(tài),引發(fā)的監(jiān)聽器自然也就是新的監(jiān)聽器,邏輯也就對了。
還是這個問題,講一個我遇到的因為兩行代碼位置相反引起的問題。
我的ListView中每行View包含一個ImageView、TextView、CheckBox。當(dāng)ListView中有一個或一個一行CheckBox被選中就讓ListView上面的Button顯示,否則就隱藏。因此,需要對每行View中的CheckBox設(shè)置監(jiān)聽。我使用CheckBox中的OnCheckedChangeListener監(jiān)聽器,當(dāng)CheckBox的狀態(tài)發(fā)生改變的時候就會觸發(fā)這個監(jiān)聽器。先看下我自定義給ListView的Adapter的getView方法中的一些關(guān)鍵代碼:
這是getView方法中使用到的內(nèi)部類:
復(fù)制代碼 代碼如下:
static class ViewHolder {
public ImageView imageView;
public TextView textView;
public CheckBox checkBox;
}
這是getView方法中利用ListView回收機制循環(huán)利用View的代碼:
復(fù)制代碼 代碼如下:
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();
}
接下來是對其中checkbox設(shè)置顯示狀態(tài)和監(jiān)聽器的代碼:
復(fù)制代碼 代碼如下:
viewHolder.checkBox
.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(
position, state));
viewHolder.checkBox.setChecked(state[position]);
之前說過了,因為ListView的回收,需要使用一個數(shù)組或list來記錄每項數(shù)據(jù)中checkbox的狀態(tài)。這里,state是與ListView列表等長的boolean數(shù)組,用于記錄每個position(也就是每個列表項數(shù)據(jù)的id)標(biāo)識的數(shù)據(jù)上checkbox應(yīng)該顯示的狀態(tài),初始的狀態(tài)都是false。構(gòu)造checkbox監(jiān)聽器的時候需要傳遞當(dāng)前View的position,以及整個列表checkbox的狀態(tài)數(shù)組state。以下是checkBox狀態(tài)改變監(jiān)聽器的代碼:
復(fù)制代碼 代碼如下:
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而決定顯示還是隱藏的按鈕。
以上整個邏輯功能的實現(xiàn)代碼。開頭說了,這是一個我因為ListView的回收機制和兩行代碼位置相反引起的問題。兩行代碼的位置相反將導(dǎo)致完全不同的結(jié)果,所指的就是設(shè)置checkbox監(jiān)聽器和狀態(tài)的兩行代碼,起初我的順序為:
復(fù)制代碼 代碼如下:
viewHolder.checkBox.setChecked(state[position]);
viewHolder.checkBox.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(position, state));
這樣的順序出現(xiàn)的問題是,當(dāng)我拉動列表后,因為拉動被隱藏的列表項狀態(tài)將被更改為false。這很不可思議,因為我已經(jīng)分離了一個狀態(tài)數(shù)組來記錄每個checkbox的狀態(tài),想來想去只有一個可能,就是狀態(tài)數(shù)組中的值改變了,而改變狀態(tài)數(shù)組的值位置就在于OnCheckedChangeListener中。Debug了幾個小時,才想通了問題就在于這兩行代碼為位置順序。
起因還是得講到ListView的回收機制。假如我的ListView最多只能顯示10個View,那么起初就會調(diào)用十次getView構(gòu)造十個全新的View(包括對其中的checkbox設(shè)置監(jiān)聽器)。當(dāng)我將列表往下拉出現(xiàn)第11個列表項的時候,頂部第一個列表項被隱藏,同樣會再調(diào)用一次getView,不過此時getView的參數(shù)將返回剛剛被隱藏的第一個列表項的View,并對這個View更改數(shù)據(jù)作為即將出現(xiàn)的第11個View。問題就出在這里,我把checkbox.setChecked()方法調(diào)用放在了設(shè)置監(jiān)聽器前面,此時因為更改了checkbox的狀態(tài),勢必引起觸發(fā)狀態(tài)更改的監(jiān)聽器。注意!由于第11個View是用被隱藏的第1個View回收來的,雖然還沒有執(zhí)行下一行設(shè)置監(jiān)聽器的代碼,但實際上它已經(jīng)擁有了一個狀態(tài)監(jiān)聽器,這個監(jiān)聽器是這個View還是作為第一個View時設(shè)置。那個時候的監(jiān)聽器設(shè)置更改的第一項的數(shù)據(jù),而不是第11項數(shù)據(jù)。因此,理所當(dāng)然不能正確更改第11項數(shù)據(jù),反而更改了無辜的第1項數(shù)據(jù)。如果我把兩行代碼順序反過來,先更改監(jiān)聽器,再設(shè)置狀態(tài),引發(fā)的監(jiān)聽器自然也就是新的監(jiān)聽器,邏輯也就對了。
相關(guān)文章
Android使用Messenger實現(xiàn)service與activity交互
這篇文章主要介紹了android使用Messenger實現(xiàn)service與activity交互的相關(guān)資料,需要的朋友可以參考下2016-06-06關(guān)于Android WebView的loadData方法的注意事項分析
本篇文章是對Android中WebView的loadData方法的注意事項進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06分享10個很棒的學(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)格模式,是用來檢測程序中違例情況的開發(fā)者工具。最常用的場景就是檢測主線程中本地磁盤和網(wǎng)絡(luò)讀寫等耗時的操作。這篇文章給大家介紹Android性能調(diào)優(yōu)利器StrictMode應(yīng)用分析,感興趣的朋友一起看看吧2018-01-01限時搶購秒殺系統(tǒng)架構(gòu)分析與實戰(zhàn)
這篇文章主要介紹了限時搶購秒殺系統(tǒng)架構(gòu)分析與實戰(zhàn) 的相關(guān)資料,需要的朋友可以參考下2016-01-01Android查看電池電量的方法(基于BroadcastReceiver)
這篇文章主要介紹了Android查看電池電量的方法,結(jié)合實例分析了Android使用BroadcastReceiver實現(xiàn)針對電池電量的查詢技巧,需要的朋友可以參考下2016-01-01Android 使用 Path 實現(xiàn)搜索動態(tài)加載動畫效果
這篇文章主要介紹了Android 使用 Path 實現(xiàn)搜索動態(tài)加載動畫效果,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下2018-08-08Android UniversalVideoView實現(xiàn)視頻播放器
這篇文章主要為大家詳細(xì)介紹了Android UniversalVideoView實現(xiàn)視頻播放器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-04-04