问题:当ListView选定的ListItem视图中存在一些UI组件,如CheckBox,希望保存状态,但实际上第一次完成时发现勾选后的选项在列表往下滑再滑回去后,状态没有保存

解决过程:

1)思考后想到这个原因是因为重用了convertView,当重用converView时,原先勾选的状态没有保存,又被新的数据源覆盖,重点代码为:

if (convertView == null) {
                convertView = getLayoutInflater().inflate(
                        R.layout.city_list_item, null);
            }
CheckBox selectedCheckBox = (CheckBox) convertView
                    .findViewById(R.id.isSelected);
CityItem data = cityItems.get(position);            //data是数据源
selectedCheckBox.setChecked(data.getSelected());
                                      //getSelected()意欲读取保存状态

视图重用

后来的做法是在数据源中添加一个isSelected变量,来记录选择值,并在checkBox上添加监听器,当勾选时触发保存事件:

 selectedCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){

                 @Override
                 public void onCheckedChanged(CompoundButton buttonView,
                         boolean isChecked) {
                     // TODO Auto-generated method stub

                     CityItem c= cityItems.get(position);
                     c.setSelected(isChecked);
                     Log.i("change2","change2"+"  "+c.toString()+" "+isChecked);
                 }

             });

监听勾选状态改变事件

注意这里有个小细节,就是传入getView时将position变量设置为final,变成一个常量,绑定到监听事件中,当勾选状态改变时会引用原先绑定好的常量去设定,这样就对应到了实际的数据源;

2)再次运行时,发现还是有问题了,状态依旧没有保存,通过跑断点发现监听事件是有触发的,但是触发的场合并没有我们想象的那样完美,你会发现重写视图时该监听事件也是被捕捉到了,为什么呢?因为 "selectedCheckBox.setChecked(c.getSelected()); "这一方法也是改变了状态值,被监听器捕捉到了,理下思路我们也就能明白了:原先视图绑定了A数据源(为测试方便,将A数据展示放在了列表头),监听器里绑定了position,勾选绑定事件触发后,将值存入,然后滑动界面,之后A数据源不可见,被绑定的视图被B项重用,这时 “CityItem c = cityItems.get(position); ” 获得的是新的数据源B,但在这时我们执行了CheckBox的状态设置语句,此时监听事件就被触发了,但监听器中绑定的依旧是原先的position,悲剧就发生了,A数据源的状态被B数据源覆盖了;

这时问题就很明显了,因为监听器中绑定的position与监听到的状态改变不一定一致,导致错乱。

3)在阅读学习了日落城的博客 http://www.cnblogs.com/wujd/archive/2012/08/17/2635309.html 关于这方面的解析,找到了解决方案:那就是通过交换设置监听事件和重用对象后的设置状态语句;一开始一直想不明白,为什么可行?后来想了一阵子终于明白了,因为监听设置提前于状态设置语句,这样每次的监听都被保证绑定了的position与触发事件的项一致,哪怕后来状态设置时再次触发了状态改变事件也已经能保证是自身的数据源正确显示。

 @Override
 public View getView(final int position, View convertView,    ViewGroup parent) {
         if (convertView == null) {
             convertView = getLayoutInflater().inflate(
                         R.layout.city_list_item, null);
         }
         CityItem c = cityItems.get(position);
             CheckBox selectedCheckBox = (CheckBox) convertView
                     .findViewById(R.id.isSelected);
             selectedCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){

                 @Override
                 public void onCheckedChanged(CompoundButton buttonView,
                         boolean isChecked) {
                     // TODO Auto-generated method stub

                     CityItem c= cityItems.get(position);
                     c.setSelected(isChecked);
                                     }

             });
             selectedCheckBox.setChecked(c.getSelected());
         return convertView;
 }

getView模块

Android之ListView——ArrayAdapter的学习与总结的更多相关文章

  1. 43.Android之ListView中BaseAdapter学习

    实际开发中个人觉得用的比较多是BaseAdapter,尽管使用起来比其他适配器有些麻烦,但是使用它却能实现很多自己喜欢的列表布局,比如ListView.GridView.Gallery.Spinner ...

  2. Android之ListView——ArrayAdapter的用法学习

    当我们使用ListView时,必不可少的便会使用到adapter,adapter的用处就像是一个水管接口,把你想展现的数据与你希望展现的布局样式通过某种协定结合起来. ArrayAdapter针对每个 ...

  3. 42.Android之ListView中ArrayAdapter简单学习

    今天学习下Android中ListView关于ArrayAdapter数据绑定, 废话少说直接上代码. 改下布局文件: <?xml version="1.0" encodin ...

  4. Android(java)学习笔记132:ListViewProject案例(ListView + ArrayAdapter)

    1.首先是MainActivity.java文件,如下: package com.himi.lv1; import java.util.ArrayList; import java.util.List ...

  5. Android(java)学习笔记74:ListViewProject案例(ListView + ArrayAdapter)

    1. 首先是MainActivity.java文件,如下: package com.himi.lv1; import java.util.ArrayList; import java.util.Lis ...

  6. Android ListView ArrayAdapter 的简单使用

    前面写了3篇关于android的文章,其中的演示程序都写在了一个工程中,当时为了方便测试就在启动页MainActivity中放了3个按钮,点击不同的按钮进入不同的示例程序页面,MainActivity ...

  7. 38.Android之ListView简单学习(一)

    android中ListView用的很普遍,今天来学习下,本篇主要以本地数据加载到listview,后面会学习从网络获取数据添加到listview. 首先改下布局文件: <?xml versio ...

  8. 转--Android实现ListView过滤功能,继承于BaseAdapter,非ArrayAdapter。

    其实实现ListView过滤功能最方便的便是使用ArrayAdapter,里面自带的getFilter()方法能很方便的实现此功能,但是在实际的开发中,一般都是继承于BaseAdapter.还有一种是 ...

  9. Android笔记: ListView基本用法-ArrayAdapter

    ListView实现过程: 新建适配器->添加数据源到适配器->视图加载适配器 数据适配器: 把复杂的数据(数组.链表.数据库.集合等)填充在制定的试图界面上. 两种常用数据适配器 Arr ...

随机推荐

  1. mysql存储emoji表情

    微信获取的用户昵称nickname中带有emoji表情,转换成字符码后是这种形式“\xF0\x9F\x91\x8D\xE6\x94...”, 直接保存可能出现以下错误 Caused by: java. ...

  2. EXT学习之——获取下拉框combobox的值与显示名

    //申请科室 var comboboxdept = new Ext.form.ComboBox({ xtype: "combobox", name: "Gender&qu ...

  3. js创建节点,小试牛刀

    实现如下的功能 非常简单的一个小训练. 思想: 1.首先创建text和一个button 代码如下. <body> <input type="text" id=&q ...

  4. threadlocal类

    1.threadlocal对象为线程提供变量的副本,该副本为线程私有的,其它线程访问不到: 2.变量的副本存储在ThreadLocalMap对象中: 3.使用threadlocal时候,最好先使用in ...

  5. teamviewer现在无法捕捉屏幕,这可能是由于快速的用户切换或远程桌面会话已经断开

    解决方法:      不用远程连接过去开启teamview,直接在在电脑本机上手动开启teamview就可以了 即:如果是mstsc远程过去开启,则会有这个错误提示,需要让服务器连接显示器,手动去登录 ...

  6. velocity模板使用建议

    复杂页面前端模块化的方式: 方式一:iframe 方式二:velocity模板(#parse) 方式一,优点很多,也有缺点,例如页面之间传递参数等: 方式二,页面之间的调用,传参更容易,页面性能更好: ...

  7. Hadoop HDFS编程 API入门系列之HdfsUtil版本2(七)

    不多说,直接上代码. 代码 package zhouls.bigdata.myWholeHadoop.HDFS.hdfs1; import java.io.FileInputStream;import ...

  8. CentOS6 搭建Git仓库

    近期上了Redmine以后,系统集成了Git的联动功能,于是萌生了搭建内网仓库的想法,特此记录一下: 1.安装Git yum -y install git 2.创建用户及密码 useradd git ...

  9. vnc

    Xvnc, Xvnc-core, vncagent, vncinitconfig, vnclicense, vnclicensehelper, vnclicensewiz, vncpasswd, vn ...

  10. JavaScript初学者应注意的七个细节(转)

    http://www.cnblogs.com/lhb25/archive/2011/01/10/1932284.html 每种语言都有它特别的地方,对于JavaScript来说,使用var就可以声明任 ...