a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 系統 > Android > 正文

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

2020-04-11 12:32:59
字體:
來源:轉載
供稿:網友
之前講到了自定義Adapter傳遞給ListView時,因為ListView的View回收,需要注意當ListView列表項中包含有帶有狀態標識控件的問題。詳情可見之前發的帖[url=自定義Adapter實現ListView帶多選框等狀態控件的注意事項 //www.5lwq4hdr.cn/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項數據。如果我把兩行代碼順序反過來,先更改監聽器,再設置狀態,引發的監聽器自然也就是新的監聽器,邏輯也就對了。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 欧美午夜理伦三级在线观看偷窥 | 免费xxxxx在线观看网站软件 | 国产精品亚洲精品日韩已方 | 亚洲国产精品99久久久久久久久 | 午夜精品久久久久久久蜜桃app | 国产成年人小视频 | 日韩精品视频国产 | 在线精品亚洲 | 婷婷久久五月天 | 国产一区二区三区久久 | 久久久999精品视频 成人激情在线 | 久久久久久久久久久久久国产精品 | 成人精品视频99在线观看免费 | 国产精品久久久久久久9999 | 黄色在线免费看 | 99久久久99久久国产片鸭王 | 最近免费中文字幕大全免费版视频 | 成人一区二区三区在线观看 | 日本国产一区二区三区 | 视频在线一区 | 亚洲国产在| 一区二区久久 | 91视频免费看网站 | 日韩一区二区三区在线播放 | 色呦呦在线看 | 色婷婷综合久久久久中文一区二区 | 久久国产精品一区二区 | 色网站免费看 | 超碰97人人干 | 一区二区三区亚洲 | 中文久久| 成人午夜电影网 | 久草视频新 | 91免费看片| 99这里只有精品 | 国产精品一区人伦免视频播放 | 欧美成人免费在线 | 久久久久久久久久一本门道91 | 精品96久久久久久中文字幕无 | 日韩精品一区在线视频 | 久久久久久久久成人 |