Android中Adapter中edittext,checkbox记住状态解决方案(一)

在上篇文章解决了adapter中checkbox记住状态和edittext可编辑的问题,下面谈谈怎么解决记住edittext中的内容和保证在操作加、减按钮的时候,操作的edittext对象是没有错位的问题。

一、记住edittext中的内容

解决的思路和checkbox差不多,不过还是有些差别,checkbox只有两种状态,而edittext的值是不固定的。checkbox我们是用一个enum类型的list来保存状态的,所以edittext就不能了,可以用map和实体类,我为了方便就用了hashMap。

// 用来存储editext中数据的listprivate List<Map<String, String>> mData = new ArrayList<Map<String, String>>();
在初始化的时候先模拟数据

for (CartBean cartBean : list) {mData.add(new HashMap<String, String>());}

edittext的监听,并且有个log

            mHolder.num.addTextChangedListener(new TextWatcher() {@Overridepublic void onTextChanged(CharSequence s, int start, int before,int count) {}@Overridepublic void beforeTextChanged(CharSequence s, int start, int count,int after) {}@Overridepublic void afterTextChanged(Editable s) {if (!TextUtils.isEmpty(s.toString())) {                                     if(!TextUtils.isEmpty(s.toString())){mData.get(position).put(etValue,s.toString()); <strong>Log.i("afterTextChanged", "position"+position);</strong>}}}});
根据list对应位置的position取出edittext的值

       String value = mData.get(position).get(etValue);if (!TextUtils.isEmpty(value)) {mHolder.num.setText(value);} else {mHolder.num.setText("1");}
代码出来了,然后在测试的时候可以发现仍然会出现错乱的问题,后来当多次来回滑动列表之后,再滑动列表,让第一个刚好完全出来,下一个刚好进来,这时候第一个item会被刚进来的item重用,执行上面的赋值代码的时候log应该是这样

01-27 15:55:46.612: I/afterTextChanged(4784): position001-27 15:55:46.622: I/afterTextChanged(4784): position101-27 15:55:46.632: I/afterTextChanged(4784): position201-27 15:55:46.642: I/afterTextChanged(4784): position301-27 15:55:46.642: D/AbsListView(4784): unregisterIRListener() is called 01-27 15:55:46.642: D/AbsListView(4784): unregisterIRListener() is called 01-27 15:55:46.662: D/AbsListView(4784): unregisterIRListener() is called 01-27 15:55:46.682: D/AbsListView(4784): unregisterIRListener() is called <strong>01-27 15:55:56.882: I/afterTextChanged(4784): position4</strong>
一个操作只触发一个监听

结果发现是这样

01-27 15:53:43.772: I/afterTextChanged(4784): position001-27 15:53:43.772: I/afterTextChanged(4784): position501-27 15:53:43.772: I/afterTextChanged(4784): position501-27 15:53:43.772: I/afterTextChanged(4784): position901-27 15:53:43.772: I/afterTextChanged(4784): position501-27 15:53:43.772: I/afterTextChanged(4784): position001-27 15:53:43.772: I/afterTextChanged(4784): position601-27 15:53:43.772: I/afterTextChanged(4784): position1501-27 15:53:43.772: I/afterTextChanged(4784): position1501-27 15:53:43.772: I/afterTextChanged(4784): position1101-27 15:53:43.772: I/afterTextChanged(4784): position601-27 15:53:43.772: I/afterTextChanged(4784): position201-27 15:53:43.772: I/afterTextChanged(4784): position801-27 15:53:43.772: I/afterTextChanged(4784): position1201-27 15:53:43.772: I/afterTextChanged(4784): position1801-27 15:53:43.772: I/afterTextChanged(4784): position1301-27 15:53:43.772: I/afterTextChanged(4784): position901-27 15:53:43.772: I/afterTextChanged(4784): position401-27 15:53:43.772: I/afterTextChanged(4784): position4
一个操作触发了很多个监听,触发了多个监听,就必然会导致多个地方的edittext的值被改变,所以才出现错乱的问题。后来我想到可能是在adapter反复执行

  mHolder.num.addTextChangedListener(new TextWatcher()
的缘故,为了证实自己的想法,我点进去看了下监听的源码,发现

 public void addTextChangedListener(TextWatcher watcher) {        if (mListeners == null) {            <strong>mListeners = new ArrayList<TextWatcher>();</strong>        }        mListeners.add(watcher);    }
原来android是用了arraylist把所有加进来的监听都存起来了,所以才会有一个操作触发多个监听的问题。那么checkbox没出现这样的原因应该是每次都重新设置监听对象了吧

 public void setOnClickListener(OnClickListener l) {        if (!isClickable()) {            setClickable(true);        }        <strong>getListenerInfo().mOnClickListener = l;</strong>    }
果然每次都重新设置一个新的。其实根据方法名能够看出来方法的用途的,一个是add,一个是set。
问题找到那就好办了,其实adapter中的viewholder对象数目是固定的,在多也只会重用了,所以我们也可以设置和viewholder一样数量的监听就行了,可以这样做

if (convertView == null) {      ....      class MyTextWatcher implements TextWatcher {public MyTextWatcher() {}       @Overridepublic void onTextChanged(CharSequence s, int start,int before, int count) {}       @Overridepublic void beforeTextChanged(CharSequence s, int start,int count, int after) {}@Overridepublic void afterTextChanged(Editable s) {if (!TextUtils.isEmpty(s.toString())) {mData.get(position).put(etValue, s.toString()); //Log.i("afterTextChanged", "position" + position);}       }}mHolder.num.addTextChangedListener(new MyTextWatcher(mHolder));}
这样只在convertview为null的时候才添加监听,这样保证了一个edittext只会有一个监听。再试试,发现还是不对,改变过的值都无法保存。出了问题还是看log

01-27 16:59:40.512: I/afterTextChanged(12344): position001-27 16:59:40.532: I/afterTextChanged(12344): position101-27 16:59:40.542: I/afterTextChanged(12344): position201-27 16:59:40.552: I/afterTextChanged(12344): position301-27 16:59:42.772: I/afterTextChanged(12344): position401-27 16:59:43.712: I/afterTextChanged(12344): position001-27 16:59:44.502: I/afterTextChanged(12344): position101-27 16:59:45.392: I/afterTextChanged(12344): position201-27 16:59:46.632: I/afterTextChanged(12344): position301-27 16:59:47.492: I/afterTextChanged(12344): position401-27 16:59:47.842: I/afterTextChanged(12344): position001-27 16:59:49.142: I/afterTextChanged(12344): position101-27 16:59:51.662: I/afterTextChanged(12344): position201-27 16:59:52.822: I/afterTextChanged(12344): position301-27 16:59:53.192: I/afterTextChanged(12344): position401-27 17:00:06.662: I/afterTextChanged(12344): position0
看到监听里面的position的值是0-4,也就是说无论列表怎么滑动,position的值都只是convertview为空的时候初始化好的。这样当第一项滚出屏幕,底下一项进入屏幕的时候,执行到这段代码

//这时代码position肯定是大于4的,假设是5,但mData中位置为5的地方是空值,这就导致第一项和第6项就都被设为1了String value = mData.get(position).get(etValue);if (!TextUtils.isEmpty(value)) {mHolder.num.setText(value);} else {mHolder.num.setText("1");}
想解决这个问题,就得在监听回调的方法里能够动态获取到position的值。这里我们可以这样做

        if (convertView == null) {......class MyTextWatcher implements TextWatcher {public MyTextWatcher(ViewHolder holder) {mHolder = holder;}/** * 这里其实是缓存了一屏数目的viewholder, 也就是说一屏能显示10条数据,那么内存中就会有10个viewholder * 在这的作用是通过edittext的tag拿到对应的position,用于储存edittext的值 */private ViewHolder mHolder;@Overridepublic void onTextChanged(CharSequence s, int start,int before, int count) {}@Overridepublic void beforeTextChanged(CharSequence s, int start,int count, int after) {}@Overridepublic void afterTextChanged(Editable s) {if (!TextUtils.isEmpty(s.toString())) {//通过tag来取position<strong> int position = (Integer) mHolder.num.getTag();</strong>mData.get(position).put(etValue, s.toString()); //Log.i("afterTextChanged", "position" + position);}}}mHolder.num.addTextChangedListener(new MyTextWatcher(mHolder));convertView.setTag(mHolder);} else {mHolder = (ViewHolder) convertView.getTag();}       //每次用position动态更新edittext的tag      <strong>mHolder.num.setTag(position);</strong>
虽然viewholder就固定的那几个,但是我们可以通过edittext的tag从而达到动态更新position值的效果。

然后再测试就会发现edittext能够记住内容了。

二、保证在操作加、减按钮的时候,操作的edittext对象是没有错位的

正常监听是这样写

mHolder.add.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {strNum = mData.get(position).get(etValue);int intnum = Integer.parseInt(strNum);intnum++;mHolder.num.setText("" + intnum);}});
但这样写在adapter中是行不通的, 因为当触发回调的时候,edittext已经不是add按钮注册监听时候的那个了,而是最后一个加载的item中的edittext。edittext的对象已经变了就是导致操作edittext错位的根本原因。这个问题的解决方法我在上篇文章里面已经说过了,就是把edittext存起来。代码我就不贴了,下面我会贴出demo链接,感兴趣的可以下载看看。有什么好的建议可以留言分享出来,共同学习。

点击前去下载Demo


更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. 《Android第一行代码》first reading 一
  3. android矢量图之VectorDrawable ,自由又方便的填充色彩
  4. Android(安卓)图片对比(图片相似度)代码
  5. android 中的监听器与内部匿名类
  6. 20172314 2017-2018-2《程序设计与数据结构》第十一周学习总结
  7. Android小项目之八 界面细节
  8. 拒绝ndk-build (Android(安卓)Native Development Kit)
  9. 10个经典的Android开源项目(线程,网络等学习不错)

随机推荐

  1. android-仿QQtab
  2. 让Android不播放关机动画,而是显示一个关
  3. Android 之经典源码
  4. android studio Build 设置简介
  5. Android实现自己的回调函数
  6. Android Wifi模块分析(六)
  7. Android——BitMap(位图)相关知识总结贴
  8. android 一键锁屏实现
  9. Android——TabHost(标签容器)相关知识总结
  10. Android对于模块启动的permission