Android中Adapter中edittext,checkbox记住状态解决方案(二)
16lz
2021-01-25
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
更多相关文章
- 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
- 《Android第一行代码》first reading 一
- android矢量图之VectorDrawable ,自由又方便的填充色彩
- Android(安卓)图片对比(图片相似度)代码
- android 中的监听器与内部匿名类
- 20172314 2017-2018-2《程序设计与数据结构》第十一周学习总结
- Android小项目之八 界面细节
- 拒绝ndk-build (Android(安卓)Native Development Kit)
- 10个经典的Android开源项目(线程,网络等学习不错)