国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

ListView的View回收引起的checkbox狀態改變監聽等問題解決方案

2020-04-11 12:32:59
字體:
來源:轉載
供稿:網友
之前講到了自定義Adapter傳遞給ListView時,因為ListView的View回收,需要注意當ListView列表項中包含有帶有狀態標識控件的問題。詳情可見之前發的帖[url=自定義Adapter實現ListView帶多選框等狀態控件的注意事項 //m.survivalescaperooms.com/article/33425.htm
還是這個問題,講一個我遇到的因為兩行代碼位置相反引起的問題。
我的ListView中每行View包含一個ImageView、TextView、CheckBox。當ListView中有一個或一個一行CheckBox被選中就讓ListView上面的Button顯示,否則就隱藏。因此,需要對每行View中的CheckBox設置監聽。我使用CheckBox中的OnCheckedChangeListener監聽器,當CheckBox的狀態發生改變的時候就會觸發這個監聽器。先看下我自定義給ListView的Adapter的getView方法中的一些關鍵代碼:
這是getView方法中使用到的內部類:
復制代碼 代碼如下:

static class ViewHolder {
public ImageView imageView;
public TextView textView;
public CheckBox checkBox;
}

這是getView方法中利用ListView回收機制循環利用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設置顯示狀態和監聽器的代碼:
復制代碼 代碼如下:

viewHolder.checkBox
.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(
position, state));
viewHolder.checkBox.setChecked(state[position]);

之前說過了,因為ListView的回收,需要使用一個數組或list來記錄每項數據中checkbox的狀態。這里,state是與ListView列表等長的boolean數組,用于記錄每個position(也就是每個列表項數據的id)標識的數據上checkbox應該顯示的狀態,初始的狀態都是false。構造checkbox監聽器的時候需要傳遞當前View的position,以及整個列表checkbox的狀態數組state。以下是checkBox狀態改變監聽器的代碼:
復制代碼 代碼如下:

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的整型,用于記錄被選中多選框的數量。searchButton是根據checkbox而決定顯示還是隱藏的按鈕。

以上整個邏輯功能的實現代碼。開頭說了,這是一個我因為ListView的回收機制和兩行代碼位置相反引起的問題。兩行代碼的位置相反將導致完全不同的結果,所指的就是設置checkbox監聽器和狀態的兩行代碼,起初我的順序為:
復制代碼 代碼如下:

viewHolder.checkBox.setChecked(state[position]);
viewHolder.checkBox.setOnCheckedChangeListener(new SearchItemOnCheckedChangeListener(position, state));

這樣的順序出現的問題是,當我拉動列表后,因為拉動被隱藏的列表項狀態將被更改為false。這很不可思議,因為我已經分離了一個狀態數組來記錄每個checkbox的狀態,想來想去只有一個可能,就是狀態數組中的值改變了,而改變狀態數組的值位置就在于OnCheckedChangeListener中。Debug了幾個小時,才想通了問題就在于這兩行代碼為位置順序。

起因還是得講到ListView的回收機制。假如我的ListView最多只能顯示10個View,那么起初就會調用十次getView構造十個全新的View(包括對其中的checkbox設置監聽器)。當我將列表往下拉出現第11個列表項的時候,頂部第一個列表項被隱藏,同樣會再調用一次getView,不過此時getView的參數將返回剛剛被隱藏的第一個列表項的View,并對這個View更改數據作為即將出現的第11個View。問題就出在這里,我把checkbox.setChecked()方法調用放在了設置監聽器前面,此時因為更改了checkbox的狀態,勢必引起觸發狀態更改的監聽器。注意!由于第11個View是用被隱藏的第1個View回收來的,雖然還沒有執行下一行設置監聽器的代碼,但實際上它已經擁有了一個狀態監聽器,這個監聽器是這個View還是作為第一個View時設置。那個時候的監聽器設置更改的第一項的數據,而不是第11項數據。因此,理所當然不能正確更改第11項數據,反而更改了無辜的第1項數據。如果我把兩行代碼順序反過來,先更改監聽器,再設置狀態,引發的監聽器自然也就是新的監聽器,邏輯也就對了。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 桃园市| 祥云县| 合川市| 岳池县| 通渭县| 都江堰市| 墨玉县| 泉州市| 山东| 信丰县| 尉犁县| 什邡市| 乌拉特前旗| 石狮市| 天门市| 尖扎县| 湖州市| 登封市| 肥城市| 化州市| 江油市| 庆元县| 同仁县| 栖霞市| 嘉定区| 青阳县| 晋中市| 黄平县| 满城县| 鹤庆县| 图片| 吉安县| 南丰县| 开阳县| 稻城县| 荔波县| 吉安市| 尼玛县| 宁波市| 双鸭山市| 苏尼特右旗|