温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

解决ListView中包含EditText数据混乱原理

发布时间:2020-08-10 11:25:28 来源:网络 阅读:5250 作者:IT学无止境 栏目:移动开发

要求:屏幕中显示一个listview,其中每一个item都有一个editText,在任一editText上输入内容,快速上下滑动,保证数据不混乱。

这是一道面试题,初看没什么,应该会很简单,但实际解决起来没那么简单,先上解决代码。

package com.zhiren.mytestok;

import android.content.Context;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;

import java.util.List;

/**
 * Created by Administrator on 2017/2/20.
 */

public class MyAdapters extends BaseAdapter {
    private Context context;
    //    private String[] str;
    private List list;

    public MyAdapters(Context context, List list) {
        this.context = context;
        this.list = list;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder;
        if (convertView == null) {
            convertView = View.inflate(context, R.layout.item_mian, null);
            viewHolder = new ViewHolder(convertView);


            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        Bean bean = (Bean) list.get(position);
        Log.e("TAG", viewHolder.text + ":" + position);
        viewHolder.text.setTag(position);
        viewHolder.text.clearFocus();


        viewHolder.text.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                int pos = (int) viewHolder.text.getTag();
                Bean b  = (Bean) list.get(pos);
                b.setName(s + "");
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        if (!TextUtils.isEmpty(bean.getName())) {
            viewHolder.text.setText(bean.getName());
        } else {
            viewHolder.text.setText("");
        }

        return convertView;
    }

    public class ViewHolder {
        private EditText text;

        public ViewHolder(View v) {
            text = (EditText) v.findViewById(R.id.et_item);
        }
    }
}

解释:解决ListView中包含EditText数据混乱原理

通过打印log可以看到,屏幕中最多可以显示7行item,下标依次为:0、1、2、3、4、5、6.

其中下标为0的item的地址值是3098e6e5

通过向上滑动,当出现第8行item(下标为7)的时候,下标为0的item已经完全看不到了,根据谷歌设计原理,下标为0的item复用到了刚刚出现的下标为7的item上,其中可以看到下标为7的item的地址值也是3098e6e5,以上可以证明。这些都是大家知道的,重点看下面:

为什么要写

viewHolder.text.setTag(position);

这一行意义重大,在滑动的过程中,动态的将item与position进行绑定,如图:

解决ListView中包含EditText数据混乱原理

那么这么做的意义是什么呢,可以看到item中的editText有一个监听事件:每当editText内容变化的时候都会将editText上的内容保存至集合中,那么保存到集合的哪一个下标中呢?看这行

int pos = (int) viewHolder.text.getTag();

被点击的那行item根据getTag()获取了最近与它绑定的那个position,还以地址为3098e6e5的item为例,那么pos的值此时应该是0还是7呢?这与当前listview滑动的位置有关,如果当前屏幕能看到下标为7的item,那么此时pos就必定为7,不可能为0,第一:item只能动态与一个position相绑定,第二,绑定是动态变化的,当前屏幕能看到的是下标为7的item,自然item与下标7绑定就不能再与下标0绑定了。那么就得到pos为7,集合就会将当前editText的内容保存到下标为7的对象中。那么无论再怎么上下滑动,只有当positon为7的时候才能从集合中获取那条保存的数据,其他position都不可以,其他item也同理。



如果正常写会出现什么呢?

例如:监听器里不getTag()

viewHolder.text.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
//                int pos = (int) viewHolder.text.getTag();
//                Bean b  = (Bean) list.get(pos);
//                b.setName(s + "");
                Bean b = (Bean) list.get(position);
                b.setName(s + "");
                Log.e("TAG", "" + position);
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });


运行app后,首先上下滑动listView到最后再滑动到开头(我设置了长度为51),让每一个item充分复用,此时再次在下标为0的item中输入内容,打印数据如下:

解决ListView中包含EditText数据混乱原理

可以看到,我只在一个item的editText中输入了1个字,按道理来说应该只触发下标为0的那个item,并将下标为0的item上的数据保存到集合,但事实上却触发了这么多item中的editText的监听,这是为什么呢?

原因是在上下快速滑动的过程中,下标为0的item出现了大量的复用情况,例如第0、7、14、21行的item都复用了这一个item,而适配器中的getView()方法经过了多次的执行,每次执行完毕后一些无用的资源就被回收了,但是item的editText是保存在viewHolder中的,并没有被回收,但是多次的执行getView()方法,每一次都让Item中的这个editText在对应的positon下设置了一次监听,那么多次设置监听,对应的是不同的位置(position),当触发监听的时候,自然会多处响应,导致了数据显示的混乱。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI