关于RecyclerView中包含Edittext的问题的几种解决方法

7,209 阅读2分钟

最近项目中有这样一个需求:购物车列表中的数量可以手动通过输入修改。通过需求判断,购物车是一个列表,列表中包含有Edittext。那么问题来了, recyclerview中包含edittext在滚动时会发生数据混乱的问题,之所以数据混乱就是因为Recyclerview的复用导致的。针对这个问题记录了几种方法来进行解决。

注:demo引用了BaseRecyclerViewAdapteHelper,故adapter继承了BaseQuickAdapter,此注释是为了防止没有看懂 convert(BaseViewHolder helper, EdittextInRecyclerViewOfBean item)这个方法

方法一:强制的停用Recyclerview的复用。

这种方法不推荐,recyclerview最大的好处之一就是复用,如果停止复用,当数据量很大,或者条目中有大图的时候会占用很大的内存,会造成卡顿或者崩溃。

helper.setIsRecyclable(false);

方法二:通过监听焦点来添加或移除Edittext的TextChangedListener来解决

在onBindViewHolder()中通过在适当的时机添加或移除Edittext的TextChangedListener来处理数据错乱的问题。这个适当的时机就是选在Edittext获得焦点的时候添加监听器,失去焦点的时候再移除监听器,这样可以保证数据的正确性。

@Override
protected void convert(BaseViewHolder helper, EdittextInRecyclerViewOfBean item) {
    EditText editText = helper.getView(R.id.et);
    editText.setText(item.getNum() + "");

    TextWatcher textWatcher = 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) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            //这里处理数据
            if (TextUtils.isEmpty(s.toString())) {
                item.setNum(0);
            } else {
                item.setNum(Integer.parseInt(s.toString()));
            }
        }
    };
    
    editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus){
                editText.addTextChangedListener(textWatcher);
            }else {
                editText.removeTextChangedListener(textWatcher);
            }
        }
    });
}

方法三:通过view的setTag()方法解决

每次填充数据之前先移除 TextWatcher 监听器,然后为 EditText 填充数据 ,最后在为 EditText 添加 TextWatcher 监听器。

@Override
protected void convert(BaseViewHolder helper, EdittextInRecyclerViewOfBean item) {
    TextWatcher textWatcher = 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) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (TextUtils.isEmpty(s.toString())) {
                item.setNum(0);
            } else {
                item.setNum(Integer.parseInt(s.toString()));
            }
        }
    };

    EditText editText = helper.getView(R.id.et);
    //为了避免TextWatcher在调用settext()时被调用,提前将它移除
    if (editText.getTag() instanceof TextWatcher) {
        editText.removeTextChangedListener((TextWatcher) editText.getTag());
    }
    editText.setText(item.getNum() + "");
    //重新添加上TextWatcher监听
    editText.addTextChangedListener(textWatcher);
    //将TextWatcher绑定到EditText
    editText.setTag(textWatcher);
}

方法四:为每个edittext的绑定位置

当相应position位置上的edittext发生变化时,对应的TextWatcher进行监听并修改相应position的数据

public class EditTextInRecyclerViewAdapter extends RecyclerView.Adapter {
    private List<EdittextInRecyclerViewOfBean> mList = new ArrayList<>();

    public void setData(List<EdittextInRecyclerViewOfBean> list) {
        this.mList = list;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_edittext, parent, false);
        return new ViewHolder(v, new ITextWatcher());
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        ViewHolder viewHolder = (ViewHolder) holder;
        viewHolder.mITextWatcher.bindPosition(position);
        viewHolder.mEditText.setText(mList.get(position).getNum()+"");
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        EditText mEditText;
        ITextWatcher mITextWatcher;

        private ViewHolder(View v, ITextWatcher watcher) {
            super(v);
            this.mEditText = v.findViewById(R.id.et);
            this.mITextWatcher = watcher;
            this.mEditText.addTextChangedListener(watcher);
        }
    }

    class ITextWatcher implements TextWatcher {
        private int position;

        private void bindPosition(int position) {
            this.position = position;
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }

        @Override
        public void afterTextChanged(Editable s) {
            if (TextUtils.isEmpty(s.toString())) {
                mList.get(position).setNum(0);
            } else {
                mList.get(position).setNum(Integer.parseInt(s.toString()));
            }
        }
    }
}