RecyclerView 在新行中显示以前在 EditText 中输入的值

Posted

技术标签:

【中文标题】RecyclerView 在新行中显示以前在 EditText 中输入的值【英文标题】:RecyclerView shows previous values entered in an EditText in new rows 【发布时间】:2018-06-02 12:37:15 【问题描述】:

我正在创建一个 android 应用程序,我在其中使用 recyclerView 并且 recyclerView 的行具有 editText

这是我的ReadingAdapter 课程

public class ReadingAdapter extends RecyclerView.Adapter<ReadingAdapter.ViewHolder>  implements AdapterView.OnItemSelectedListener 

    Context context;
    String valOpenReading, valClosReading, valConsumption;
    private List<ReadingData> readingList;
    static String[] arrValOpenRead, arrValClosRead, arrValConsumption;
    public ReadingAdapter(Context context, List<ReadingData> readingList) 
        this.context = context;
        this.readingList = readingList;

        arrValOpenRead = new String[readingList.size()];
        arrValClosRead = new String[readingList.size()];
        arrValConsumption = new String[readingList.size()];
    

    @Override
    public ReadingAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.reading_sheet_layout, parent, false);
        return new ReadingAdapter.ViewHolder(view);
    

    @Override
    public void onBindViewHolder(final ReadingAdapter.ViewHolder holder, final int position) 
        ReadingData tempData = readingList.get(position);
        holder.pdtName.setText(tempData.pdtName);
        holder.keyId.setText("Key "+tempData.keyId);

        holder.etClosRead.addTextChangedListener(new TextWatcher() 
            boolean ignore = false;
            @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 (ignore)
                    return;
                ignore = true;
                valOpenReading = holder.etOpenRead.getText().toString();
                arrValOpenRead[position] = valOpenReading;
                valClosReading = s.toString().equals("") ? "0": s.toString();
                arrValClosRead[position] = valClosReading;
                if (!valOpenReading.equals("")) 
                    if (Integer.parseInt(valClosReading) < Integer.parseInt(valOpenReading)) 
                        Toast.makeText(context, "Check once! closing reading should be more than opening reading!", Toast.LENGTH_LONG).show();
                        valConsumption = "0";
                        holder.consumption.setText("");
                     else 
                        valConsumption = (Integer.parseInt(valClosReading) - Integer.parseInt(valOpenReading))+"";
                        arrValConsumption[position] = valConsumption;
                        holder.consumption.setText(valConsumption);
                    
                 else
                    Toast.makeText(context, "Please fill the opening reading!", Toast.LENGTH_SHORT).show();
                ignore = false;
            
        );
    

    @Override
    public int getItemCount() 
        return readingList.size();
    

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) 

    

    @Override
    public void onNothingSelected(AdapterView<?> parent) 

    

    public class ViewHolder extends RecyclerView.ViewHolder
        TextView pdtName, keyId, consumption;
        EditText etOpenRead, etClosRead;
        public ViewHolder(View view) 
            super(view);
            pdtName = (TextView)view.findViewById(R.id.txt_list_pdt_supp);
            keyId = (TextView)view.findViewById(R.id.key_set);
            etOpenRead = (EditText)view.findViewById(R.id.open_val_set);
            etClosRead = (EditText)view.findViewById(R.id.clos_val_set);
            consumption = (TextView)view.findViewById(R.id.consumption_val);
        
    

这是我的ReadingData.java

public class ReadingData 
    String pdtName, keyId, openReading, closReading, consumption;
    public ReadingData(String pdtName, String keyId) 
        this.pdtName = pdtName;
        this.keyId = keyId;
    

在这里,如果我在 recyclerView 的起始项目中输入值,那么当我将项目向上滚动到列表底部时,最后一个项目将具有该值。

请忽略图像质量,因为我们无法上传超过 2MiB 的快照。

这里视图在列表滚动时被回收。如何防止将值复制到列表中的其他项目。

而且Toast 也重复了好几次。如何阻止这种情况。

更新: 通过LQ Gioan 到SO question How ListView's recycling mechanism works 的建议,我得到了ListView 实际如何与视图回收一起工作的逻辑。

但我不确定recyclerView 是否也同样有效。

但在我的情况下,我该如何实现这个过程。请有人在这里帮助我。

【问题讨论】:

ListView 重用屏幕上不可见的项目视图。你应该看看这个答案来理解:***.com/questions/11945563/…。要解决您的问题,您应该将用户留下的数据保存在ReadingData 中。每次调用 getView 方法时,您将这些数据设置回 EditText(s) 感谢您的链接。现在我明白了listView 的工作原理。但是我应该在我的情况下使用什么?我怎样才能在不回收视图的情况下实现这一目标?我应该在这里使用recyclerView 吗? 如果你想在不回收的情况下使用ListView,那么你在你的代码中删除if (convertView == null)。但是,如果您的列表中有很多项目,您可以获得OutOfMemoryException。所以我强烈推荐你在ListView 中使用回收。您可以在我的第一条评论中尝试我的解决方案 ReadingData 仅用于绑定变量。对此感到抱歉,但我不明白解决方案。你能解释一下吗? 您可以将TextWatcher 用于EditText(s) 来观看用户使用EditText.addTextChangedListener(TextWatcher)(example here) 输入的任何内容。然后,将新变量添加到ReadingData(或创建一个新对象-> 由您决定)以保留这些输入数据。任何时候调用 getView 方法,您都可以将这些输入数据设置回 EditText(s)。 【参考方案1】:

RecyclerView 重用视图,实际上它只生成与屏幕上可见的视图一样多的视图。因此,如果您可以看到为其他行设置的值,则可以预期

解决方案是将要更改的视图的所有属性设置为默认值或数据集中应显示的任何行

所以将addTextChangedListener insode ViewHolder 构造函数(您可以通过调用getAdapterPosition() 来获取位置)以获得更好的性能,并从您的数据集中将editText 值设置在onBindViewHolder 方法中

【讨论】:

感谢您的建议。它就像一个魅力。【参考方案2】:

您的活动代码:

ListView listview = (ListView) findViewById(R.id.list_view);
listview.setItemsCanFocus(true);
Adapter adapter = new Adapter (YourActivity.this, YourArrayList);
listview .setAdapter(adapter);

适配器类

public class Adapter extends BaseAdapter 

// Declare Variables \\
Context mContext;
LayoutInflater inflater;
Activity act;
String[] temp;


public Adapter(Context context, ArrayList<String> list) 
    mContext = context;
    inflater = LayoutInflater.from(mContext);
    act = (Activity) context;
    //-------Temp String Array-------\\
    temp = new String[this.count];
    for (int i = 0; i < this.count; i++) 
        temp[i] = list.get(i);
    
    //---------------------------\\



public class ViewHolder 
    TextView optionTitle;
    EditText optionText;
    int ref;


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


@Override
public Object getItem(int position) 
    return temp[position];


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


public View getView(final int position, View view, ViewGroup parent) 
    final ViewHolder holder;
    if (view == null) 
        holder = new ViewHolder();
        view = inflater.inflate(R.layout.lv_items_add_ques_options_mcq, null);
        holder.optionTitle = (TextView) view.findViewById(R.id.add_ques_opts_count_mcq_tv);
        holder.optionText = (EditText) view.findViewById(R.id.add_ques_opts_title_mcq_et);
        view.setTag(holder);
     else 
        holder = (ViewHolder) view.getTag();
    
    holder.ref = position;

    holder.optionTitle.setText(getCharForNumber(position) + ":");

    holder.optionText.setText(temp[position]);
    holder.optionText.addTextChangedListener(new TextWatcher() 

        @Override
        public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) 
        

        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
                                      int arg3) 
        

        @Override
        public void afterTextChanged(Editable arg0) 
            temp[holder.ref] = arg0.toString().trim();
        
    );

    return view;


public void getList() 
    StaticValues.arrayListOptions = new ArrayList<String>(Arrays.asList(temp));
    StaticValues.arrayListOptionsCount = new ArrayList<String>();
    for (int i = 0; i < count; i++) 
        StaticValues.arrayListOptionsCount.add(String.valueOf(i+1));
        Log.e("err_al", StaticValues.arrayListOptions.get(i));
        Log.e("err_al", StaticValues.arrayListOptionsCount.get(i));
    


private String getCharForNumber(int i) 
    char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    if (i > 25) 
        return null;
    
    return Character.toString(alphabet[i]);

【讨论】:

感谢您的回答。从适配器返回的视图,没有被回收吗? 好吧,我们将 EditText 数据保存到一个临时数组中,该数组用于保存数据,因此即使它被回收,您的数据也将保持不变。 this.count = Integer.parseInt(count); : Integer.parseInt(count) 中的计数值来自适配器类的哪里? 我已经编辑了答案,请检查,this.count 是一个额外的东西。对你没用。 我收到了java.lang.NullPointerException

以上是关于RecyclerView 在新行中显示以前在 EditText 中输入的值的主要内容,如果未能解决你的问题,请参考以下文章

替换而不是将项目添加到 Arraylist

从数据库检索到 jsp 的数据中的新行

ScrollView嵌套recyclerView出现的滑动问题

谷歌操作中基本卡的新行

RecyclerView 的 IBinder RuntimeException,但它不会使应用程序崩溃

一起滚动多个水平RecyclerView