`
52xianmengyu
  • 浏览: 63880 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类

Android ListView CheckBox状态错乱

 
阅读更多
listView中包含checkBox的时候,经常会发生其中的checkBox错乱的问题,大多时候的代码如下:
先看一下效果图:奇数行为选中状态,偶数行为非选中状态


具体代码:
布局文件:

1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3     android:layout_width="fill_parent"
4     android:layout_height="fill_parent"
5     android:orientation="horizontal" >
6    
7     <LinearLayout
8         android:id="@+id/layout"
9         android:layout_width="fill_parent"
10         android:layout_height="fill_parent">
11        
12         <TextView
13             android:id="@+id/textView"
14             android:layout_width="wrap_content"
15             android:layout_height="wrap_content"/>
16    
17         <CheckBox
18             android:id="@+id/checkBox"
19             android:layout_width="wrap_content"
20                 android:layout_height="wrap_content"/>
21        
22     </LinearLayout>
23    
24 </LinearLayout>

JAVA CODE:

  1 package com.tony.ui.listview;
  2
  3 import java.util.ArrayList;
  4 import java.util.List;
  5
  6 import com.tony.R;
  7
  8 import android.app.Activity;
  9 import android.os.Bundle;
10 import android.view.LayoutInflater;
11 import android.view.View;
12 import android.view.ViewGroup;
13 import android.widget.BaseAdapter;
14 import android.widget.CheckBox;
15 import android.widget.CompoundButton;
16 import android.widget.CompoundButton.OnCheckedChangeListener;
17 import android.widget.LinearLayout;
18 import android.widget.ListView;
19 import android.widget.TextView;
20
21 public class ListViewCheckBox extends Activity{
22    
23     private ListView listView;
24     private List<A> list;
25     private Adapter1 adapter1;
26    
27     @Override
28     protected void onCreate(Bundle savedInstanceState) {
29         super.onCreate(savedInstanceState);
30         setContentView(R.layout.listview_checkbox);
31         initDate();
32         listView = (ListView)findViewById(R.id.listView);
33         adapter1 = new Adapter1();
34         listView.setAdapter(adapter1);
35     }
36    
37    
38     /**
39      * 模拟40个数据,奇数数据为选中状态,偶数数据为非选中状态
40      */
41     private void initDate(){
42         list = new ArrayList<A>();
43         A a;
44         for(int i=0;i<40;i++){
45             if(i%2==0){
46                 a = new A(i+"号位",A.TYPE_NOCHECKED);
47                 list.add(a);
48             }else{
49                 a = new A(i+"号位",A.TYPE_CHECKED);
50                 list.add(a);
51             }
52         }
53     }
54    
55     class Adapter1 extends BaseAdapter{
56
57         @Override
58         public int getCount() {
59             return list.size();
60         }
61
62         @Override
63         public Object getItem(int position) {
64             return null;
65         }
66
67         @Override
68         public long getItemId(int position) {
69             return 0;
70         }
71
72         @Override
73         public View getView(int position, View convertView, ViewGroup parent) {
74             final int index = position;
75             ViewHolder viewHolder;
76             if(convertView == null){
77                 viewHolder = new ViewHolder();
78                 convertView = LayoutInflater.from(ListViewCheckBox.this).inflate(R.layout.listview_checkbox_item, null);
79                 viewHolder.layout = (LinearLayout)convertView.findViewById(R.id.layout);
80                 viewHolder.textView = (TextView)convertView.findViewById(R.id.textView);
81                 viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.checkBox);
82                 convertView.setTag(viewHolder);
83             }else{
84                 viewHolder = (ViewHolder)convertView.getTag();
85             }
86            
87            
88             viewHolder.textView.setText(list.get(position).name);
89             if(list.get(position).type == A.TYPE_CHECKED){
90                 viewHolder.checkBox.setChecked(true);
91             }else{
92                 viewHolder.checkBox.setChecked(false);
93             }
94            
95             /*点击checkBox所在行改变checkBox状态*/
96             /*final ViewHolder vv = viewHolder;
97             viewHolder.layout.setOnClickListener(new OnClickListener() {
98                 @Override
99                 public void onClick(View v) {
100                     if(vv.checkBox.isChecked()){
101                         vv.checkBox.setChecked(false);
102                         list.get(index).type = TYPE_CHECKED;
103                     }else{
104                         vv.checkBox.setChecked(true);
105                         list.get(index).type = TYPE_NOCHECKED;
106                     }
107                    
108                 }
109             });*/
110            
111             viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
112                 @Override
113                 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
114                     if(isChecked){
115                         list.get(index).type = A.TYPE_CHECKED;
116                     }else{
117                         list.get(index).type = A.TYPE_NOCHECKED;
118                     }
119                 }
120             });
121            
122             return convertView;
123         }
124     }
125    
126     class ViewHolder{
127         LinearLayout layout;
128         TextView textView;
129         CheckBox checkBox;
130     }
131    
132     class A {
133        
134         public static final int TYPE_CHECKED = 1;
135         public static final int TYPE_NOCHECKED = 0;
136        
137         String name;
138         int type;
139        
140         public A(String name,int type){
141             this.name = name;
142             this.type = type;
143         }
144     }
145 }


以上代码就是根据List集合中的对象的类型来设置checkBox是否为选中状态,当用户点击checkBox的时候,程序根据checkBox是否选中来将其状态保存至list集合对象中,相信很多人第一次做的时候会信心满满地认为这样的逻辑简直天衣无缝。但结果是,测试的时候还没有点击checkBox来改变其状态,只是简单地上下拉动listView的时候就会发现,好像事情没有想象的那么简单。
效果图如下:

只要视力不算太差的人便一眼可以看出,按照程序的逻辑怎么连续两个checkBox的状态会一样呢,恩,肯定是模拟器神经错乱了。

解决方案:
  很多人给出的两种解决办法
  1:上来就说是因为convertview对象共用的原因,不能用convetView,而是每次getView()的时候都new一个对象的view出来.这种办法大概是用屁股想出来的.
  2:即然错乱,那我就自己再弄一个集合保存checkBox的状态,再错乱,弄死你.即然adapter里有一个list集合里保存checkBox的状态了,为什么还要自己再保存一次checkBox的状态呢,不是多此一举吗?

  PS:提供这两种办法的人都没有解释到底是为什么错乱.下面来尝试分析一下:
  1:首先分析下viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener()...);
     这句话,就是给checkBox添加一个监听器,如果checkBox的状态改变了,那么系统就会自动回调里面的onCheckedChange()方法.
         而文中onCheckedChange()方法里写的是记录这次改变后checkBox状态的代码.
  2:再接着分析下if(list.get(position).type == A.TYPE_CHECKED){...},这部分代码是根据list集合里的对象属性初始化view里checkBox是否应该是选择状态.
  3:我上下滑动listView的时候,checkBox的状态就错乱了,根据第二点的分析,无论如何checkBox的状态都不会错乱,除非list集合里对象的属性已经被改变了,到底是什么地方改变了它?
  4:文中只有一个地方写了改变list集合里checkBox对象属性的地方,那就是第一点里提到的OnCheckedChangeListener()方法。它被执行了?
   怎么回事,不可能吧,打个断点,跑一下便知上下滑动listView的时候确实停了下来.
  5:这便是convertView的功能,因为不管listView里显示多少条数据,都只是共用那么几个对象,然后我们的代码每一次把得到的对象重新赋值而已。
   对了,正是在这赋值的时候出了问题,假设android系统给我们生成了10个共用view对象,第一个view对象在第一屏的时候需要显示成"未选择"状态,而到了第二屏的时候,却要显示成"选择"状态,但由于是共用的同一个对象,根据第一点得知当checkBox的状态改变的时候,会调用onCheckedChange()方法。
  6:也许有人会怀疑就算它调用了onCheckedChanged()方法,那又如何?onCheckedChange()方法里的代码还是将当前是否为选中状态保存到了list集合里,当我再次显示时还是会根据第二点里提到的代码来正确地显示,是的,代码会根据当前index来改变list集体的属性.关键就在这里,这个index真的是对的吗?测试一下便知:
    
    在onCheckedChange()方法里打印一下index, 当快速向下滑动的时候,index的值如下: 
    

  7:共用的对象有10(这里举例,并不是一定)个,当onCheckedChange()方法调用的时候,至少也是共用对象用光的时候,再从第一个共用对象用的时候才会打印,那时的index也应该是从10开始,为什么打印的结果里会出现0?
  8:这是由于代码的顺序决定的,根据上面的代码可以看出,添加监听器的代码在初始化checkBox属性的代码之后,也就是说当初始化checkBox属性时,由于可能改变其状态,导致调用了onCheckedChange()方法,而这个监听器是在上一次初始化的时候添加的,那么当然其index就是上一次的positon值,而不是本次的,所以每次保存checkBox属性状态的时候,都把值赋到的list集合里其它对象上去了,而不是与本次index相关的对象上,这才是发生莫名其妙错乱的真正原因.
  9:解决办法:由于是因为index错误造成的,那么只要保证index值与当前positon保持一至即可,只要把添加监听器的方法加到初始化view中checkBox状态的代码之前即可.这样即始由于初始化造成调用了onCheckedChange()方法,也因为其中index值是最新的,而依然不会错乱.

代码示例:

1 class Adapter1 extends BaseAdapter{
2
3         @Override
4         public int getCount() {
5             return list.size();
6         }
7
8         @Override
9         public Object getItem(int position) {
10             return null;
11         }
12
13         @Override
14         public long getItemId(int position) {
15             return 0;
16         }
17
18         @Override
19         public View getView(int position, View convertView, ViewGroup parent) {
20             final int index = position;
21             ViewHolder viewHolder;
22             if(convertView == null){
23                 viewHolder = new ViewHolder();
24                 convertView = LayoutInflater.from(ListViewCheckBox.this).inflate(R.layout.listview_checkbox_item, null);
25                 viewHolder.layout = (LinearLayout)convertView.findViewById(R.id.layout);
26                 viewHolder.textView = (TextView)convertView.findViewById(R.id.textView);
27                 viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.checkBox);
28                 convertView.setTag(viewHolder);
29             }else{
30                 viewHolder = (ViewHolder)convertView.getTag();
31             }
32            
33             viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
34                 @Override
35                 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
36                     if(isChecked){
37                         list.get(index).type = A.TYPE_CHECKED;
38                     }else{
39                         list.get(index).type = A.TYPE_NOCHECKED;
40                     }
41                 }
42             });
43            
44             viewHolder.textView.setText(list.get(position).name);
45             if(list.get(position).type == A.TYPE_CHECKED){
46                 viewHolder.checkBox.setChecked(true);
47             }else{
48                 viewHolder.checkBox.setChecked(false);
49             }
50             return convertView;
51         }
52     }



总结:
  其实解决办法就一句话,"只要把添加监听器的方法加到初始化view中checkBox状态的代码之前即可. "


原文:http://www.cnblogs.com/wujd/archive/2012/08/17/2635309.html
分享到:
评论

相关推荐

    Android完美解决ListView复用导致的Checkbox状态混乱问题

    然而,ListView的复用机制有时会导致一些问题,特别是在涉及复选框(Checkbox)的状态管理时。本篇文章将详细探讨这个问题,并提供一个完美的解决方案。 一、问题背景 ListView通过ViewHolder模式实现高效的滚动...

    解决ListView嵌套CheckBox滑动时选中状态错乱

    总结来说,解决ListView嵌套CheckBox滑动时的选中状态错乱问题,需要深入理解ListView的工作机制,合理利用ViewHolder,正确绑定数据,监听并处理CheckBox的状态变化,以及适当地处理点击事件。通过这些步骤,可以...

    android listview 里面使用checkbox

    - 由于ListView会复用item视图,所以需要在`getView()`中正确设置Checkbox的状态,防止状态错乱。 - 使用`convertView`来重用已有的视图,减少视图的创建,提高性能。 6. **代码示例**: - 创建自定义Adapter类...

    Android中ListView结合CheckBox获取选中项.rar

    - 当ListView滚动时,由于View的复用,可能会出现CheckBox状态错乱的情况。因此,在`getView()`方法中,必须根据`ItemModel`的状态初始化CheckBox,确保每个可见的CheckBox状态正确。 9. **注意滑动冲突** - 如果...

    完美解决ListView和CheckBox的焦点冲突及CheckBox的复用问题

    在Android开发中,ListView是常用的数据展示组件,它允许用户滚动查看大量的数据项。然而,当ListView中的元素包含可交互的控件,如CheckBox时,会遇到一些常见问题,如焦点冲突和视图复用导致的显示异常。本文将...

    listview的checkbox状态保存及内存优化

    然而,在处理包含复选框(CheckBox)的ListView时,开发者经常会遇到一些棘手的问题,比如复用的convertView导致的checkbox状态错乱。本文将深入探讨如何解决这个问题,并进行相应的内存优化。 一、ListView的工作...

    ListView CheckBox

    因此,务必在`getView()`中正确设置CheckBox的状态,防止状态错乱。 - 使用`ViewHolder`模式可以提高ListView的滚动性能。 9. **点击事件处理**: - 需要区分点击事件是针对CheckBox还是ListView本身,可以重写`...

    listview解决条目错乱

    然而,在实际使用过程中,特别是当ListView的item中包含可交互的组件,如Checkbox、ToggleButton等时,用户滚动ListView时可能会遇到条目错乱的现象。这种情况主要是由于ListView的复用机制导致的,为了解决这个问题...

    android listview+checkbox

    - 由于ListView的视图复用机制,直接在Adapter的getView()中改变Checkbox的状态可能导致状态错乱。因此,需要维护一个数据结构(如List)来记录每一项的选择状态。 - 当Checkbox状态改变时,更新对应位置的数据...

    【Android】ListView与CheckBox的完美结合

    - 为了避免CheckBox状态错乱,应重写convertView的复用逻辑,确保每次显示的CheckBox状态与数据结构对应。 - 使用ViewHolder模式减少findViewById的次数,提高列表滚动时的性能。 7. **多选事件处理** - 可以...

    android listview+checkbox示例

    "android listview+checkbox示例"是针对这种场景的具体实现,它解决了在使用ListView和Checkbox时常见的两个问题:漏选和滑动后的状态错乱。 首先,让我们深入理解这两个问题。在ListView中,由于数据的复用机制...

    Listview+Edittext和ListView+CheckBox

    - 可以为ListView设置`OnCheckedChangeListener`监听CheckBox状态的变化,更新对应的数据项。 - 或者,在`getView()`中为每个CheckBox设置单击事件监听器,手动同步数据源和界面状态。 6. **优化性能**: - 为了...

    完美解决Listview嵌套Checkbox滑动后位置错乱问题,和checkbox的全选或全不选。

    本文将深入探讨如何完美解决ListView中Checkbox滑动后位置错乱的问题,以及实现Checkbox的全选和全不选功能。 首先,我们遇到的主要问题是ListView的视图复用机制。为了提高性能,ListView在滑动时会复用已滚动出...

    自定义ListView加CheckBox

    在Android开发中,ListView是一种常用的组件,用于展示大量的数据列表。然而,为了提供更丰富的交互体验,我们常常需要在ListView的每一项中添加CheckBox,从而实现单选、多选、全选和反选功能。本教程将深入讲解...

    ListView+CheckBox

    在Android开发中,ListView是一种常用的控件,用于展示大量数据列表。它允许用户滚动查看多个...通过定制适配器和正确保存状态,我们可以确保ListView中的CheckBox能够正确地反映用户的选择,避免出现状态错乱的问题。

    ListView带CheckBox 你懂的

    "ListView带CheckBox"的主题,主要涉及如何在ListView的每个列表项中集成CheckBox,并处理滑动过程中可能出现的选中状态错乱问题,以及实现全选、反选等高级功能。下面将详细介绍这些关键知识点。 1. **自定义...

    listview+checkbox乱序问题解决demo

    然而,在ListView中集成Checkbox控件时,经常会出现一个问题:当用户滚动ListView时,Checkbox的状态会错乱,即原本勾选的项可能在滚动后变为未勾选,或者原本未勾选的项变成了勾选状态。这个问题被称为“ListView...

    ListView中嵌套CheckBox

    下载积分被CSDN设置了50积分,非本人所为。没有积分的可以参看这篇文章。文章中代码基本都贴出来了。https://blog.csdn.net/qq_20521573/article/details/52073472

    listview上拉加载chackbox复用

    然而,在实现ListView时,尤其是当列表项包含可交互元素如Checkbox时,需要处理好视图复用的问题,以防止出现状态错乱的现象。本文将深入探讨"ListView上拉加载Checkbox复用"这一主题,帮助开发者理解和解决在...

    CheckBoxDemo

    demo实现了listview嵌套checkbox实现全选、反选、取消等功能,解决了listview滑动后checkbox状态错乱

Global site tag (gtag.js) - Google Analytics