RecyclerView textChangeListener 或数据绑定

RecyclerView textChangeListener or databinding

我有一个 RecylerView,其中每一行都有一个 EditText。这个EditText是给用户输入玩家名字的。当用户输入名称时,我需要 Adapter 正在查看的列表以某种方式更新。

首先我想我会在 EditText 上放一个 textChangedListener ,这部分有效。 问题是当用户添加新行或删除行时,似乎每个 EditText 的侦听器在 Adapter 上调用 notifyDataSetChanged() 时都会被调用。 notifyDataSetChanged() 也从 textChangedListener 调用,给出错误

Cannot call this method while RecyclerView is computing a layout or scrolling android.support.v7.widget.RecyclerView.

另一种选择 是不使用 textChangedListener 而是仅在用户添加一行、删除一行或开始游戏时才更新适配器列表。但是为此,我不知何故需要从 RecyclerView 中存在的所有 editTexts 中获取信息,但我还没有找到这样做的方法。如果这是可能的,我可以简单地清除适配器列表,并在每次调用 notifyDataSetChanged() 时替换为用户放入 recyclerView 的任何内容。

第三个选项 是使用 data binding。我一直在尝试遵循指南,但没有成功。绑定必须使 editTexts 直接更新适配器列表,并且最好在列表更改时更新 EditText,但这并不重要。

关于如何最好地实施它有什么想法吗?

public class ReviewAdapter extends RecyclerView.Adapter<ReviewAdapter.MyViewHolder> {

private ArrayList<String> data;

public ReviewAdapter(ArrayList<String> data) {

    this.data = data;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    Context c = parent.getContext();
    LayoutInflater inflater = LayoutInflater.from(c);
    View view = inflater.inflate(R.layout.custom_row, parent, false);
    MyViewHolder holder = new MyViewHolder(view);

    return holder;
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {

    holder.txtPlayerName.setText(data.get(position));
    holder.txtRowNumber.setText(position+1 + "");
    holder.btnRemoveRow.setOnClickListener(new MyClickListener(position, holder.btnRemoveRow));
    holder.txtPlayerName.addTextChangedListener(new MyTextWatcher(position));

}

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

class MyClickListener implements View.OnClickListener {

    private int pos;
    Button button;


    public MyClickListener(int _pos, Button _button) {
        super();
        pos = _pos;
        button = _button;


    }

    @Override
    public void onClick(View view) {
        data.remove(pos);
        System.out.println("MyClickListener.onClick.pos: " + pos);
        MainActivity.txtPlayers.setText(data.size() + " players");
        ReviewAdapter.this.notifyDataSetChanged();
    }
}

class MyTextWatcher implements TextWatcher {

    int pos;

    public MyTextWatcher(int pos) {
        this.pos = pos;
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    }

    @Override
    public void onTextChanged(CharSequence s, int i, int i1, int i2) {
        data.set(pos, s.toString());
        notifyDataSetChanged();

    }

    @Override
    public void afterTextChanged(Editable editable) {
    }
}


class MyViewHolder extends RecyclerView.ViewHolder {

    EditText txtPlayerName;
    TextView txtRowNumber;
    Button btnRemoveRow;

    public MyViewHolder(View view) {
        super(view);

        txtPlayerName = itemView.findViewById(R.id.listText);
        txtRowNumber = itemView.findViewById(R.id.listIcon);
        btnRemoveRow = itemView.findViewById(R.id.btnRemove);
    }
}
}

修改并缩小了您的适配器 class。永远不要在 onBindViewHolder 内分配 onClickListener 而不是 class 你可以使用这个可能会解决你的问题。

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.ArrayList;

public class ReviewAdapter extends RecyclerView.Adapter<ReviewAdapter.MyViewHolder> {

    private ArrayList<String> data;
    private Context mContext;

    public ReviewAdapter(Context mContext, ArrayList<String> data) {
        this.mContext=mContext;
        this.data = data;
    }

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

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {

        holder.txtPlayerName.setText(data.get(position));
        holder.txtRowNumber.setText(String.valueOf(position + 1));

    }

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


    class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, TextWatcher {

        EditText txtPlayerName;
        TextView txtRowNumber;
        Button btnRemoveRow;

        public MyViewHolder(View view) {
            super(view);

            txtPlayerName = itemView.findViewById(R.id.listText);
            txtRowNumber = itemView.findViewById(R.id.listIcon);
            btnRemoveRow = itemView.findViewById(R.id.btnRemove);
            btnRemoveRow.setOnClickListener(this);
            txtPlayerName.addTextChangedListener(this);
        }

        @Override
        public void onClick(View view) {
            if (view == btnRemoveRow) {
                data.remove(getAdapterPosition());
                System.out.println("MyClickListener.onClick.pos: " + getAdapterPosition());
                MainActivity.txtPlayers.setText(data.size() + " players");
                notifyDataSetChanged();
            }
        }

        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence s, int i, int i1, int i2) {
            data.set(getAdapterPosition(), s.toString());
            //notifyItemChanged(getAdapterPosition());

        }

        @Override
        public void afterTextChanged(Editable editable) {

        }
    }
}

在适配器实现中 View.OnFocusChangeListener

@Override
public void onBindViewHolder(Viewholder holder, int position) {
editText.setText(model.getValue());
editText.setOnFocusChangeListener(this);
editText.setTag(position);
}

@Override
public void onFocusChange(View v, boolean hasFocus) {
if (v.getTag() == null)
    return;
int position = (int) v.getTag();
if (!hasFocus && v instanceof EditText)
    mValues.get(position).setValue(((EditText) v).getText().toString());
}