简体   繁体   English

如何在Recycler视图中自动更新商品数据?

[英]How to automatically update items data in recycler view?

Let's say there's an RecyclerView consisting of CardView in it,in each card ie item there are two TextView one is for name of the device and another is for the rssi level ,so when user refreshes the the data then only rssi will get refresh rather whole list get refresh. 假设其中有一个包含CardViewRecyclerView ,在每个卡中,即项目中有两个TextView一个用于表示设备名称,另一个用于rssi级别,因此,当用户刷新数据时,只有rssi会刷新整个数据列表刷新。

I have got the data in the RecyclerView but it get's repeated rather than updating it. 我已经在RecyclerView获得了数据,但是重复了它而不是对其进行了更新。

Model class:- 型号类别:-

import android.support.annotation.NonNull;

public class RepeaterModel implements Comparable,Cloneable{

    public String macdev;
    public int rssi ;
    public int imageid;

    public RepeaterModel(String macdev, int rssi, int imageid) {
        this.macdev = macdev;
        this.rssi = rssi;
        this.imageid = imageid;
    }

    public String getMacdev() {
        return macdev;
    }

    public void setMacdev(String macdev) {
        this.macdev = macdev;
    }

    public int getRssi() {
        return rssi;
    }

    public void setRssi(int rssi) {
        this.rssi = rssi;
    }

    public int getImageid() {
        return imageid;
    }

    public void setImageid(int imageid) {
        this.imageid = imageid;
    }



    @Override
    public int compareTo(@NonNull Object o) {
        RepeaterModel compare =(RepeaterModel)o;
        if(compare.getMacdev().equals(this.macdev) && compare.getImageid()==this.imageid && compare.getRssi()==this.rssi)
        {
            return 0;
        }
        return 1;
    }

    @Override
    public RepeaterModel clone()
    {
        RepeaterModel clone;
        try {
            clone = (RepeaterModel) super.clone();

        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e); //should not happen
        }

        return clone;

    }
}

Device Adapter class:- 设备适配器类:-

public class ReapeaterDeviceAdapter extends RecyclerView.Adapter<ReapeaterDeviceAdapter.CryptoViewHolder> {

    private ArrayList<RepeaterModel> data;

    public class CryptoViewHolder extends RecyclerView.ViewHolder {

        private TextView mName, mPrice;

        public CryptoViewHolder(View itemView) {
            super(itemView);
            mName = itemView.findViewById(R.id.txtName);
            mPrice = itemView.findViewById(R.id.txtPrice);
        }
    }

    public ReapeaterDeviceAdapter(ArrayList<RepeaterModel> data) {
        this.data = data;
    }

    @Override
    public CryptoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.repeater_dev_data,parent, false);
        return new CryptoViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(CryptoViewHolder holder, int position) {
        holder.mName.setText(data.get(position).macdev);
        holder.mPrice.setText(String.valueOf(data.get(position).rssi));
    }

    @Override
    public void onBindViewHolder(CryptoViewHolder holder, int position, List<Object> payloads) {

        if (payloads.isEmpty()) {
            super.onBindViewHolder(holder, position, payloads);
        } else {
            Bundle o = (Bundle) payloads.get(0);

            for (String key : o.keySet()) {
                if (key.equals("price")) {
                    holder.mName.setText(data.get(position).macdev);
                    holder.mPrice.setText(String.valueOf(data.get(position).rssi));
                    holder.mPrice.setTextColor(Color.GREEN);
                    this.notifyItemChanged(position);
                }
            }
        }
    }

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

    public ArrayList<RepeaterModel> getData() {
        return data;
    }

    public void setData(ArrayList<RepeaterModel> newData) {

        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffUtilCallBack(newData, data));
        diffResult.dispatchUpdatesTo(this);
        data.clear();
        this.data.addAll(newData);
        //this.notifyDataSetChanged();
    }
}

DiffUtilCallback class:- DiffUtilCallback类:-

public class MyDiffUtilCallBack extends DiffUtil.Callback {
    ArrayList<RepeaterModel> newList;
    ArrayList<RepeaterModel> oldList;

    public MyDiffUtilCallBack(ArrayList<RepeaterModel> newList, ArrayList<RepeaterModel> oldList) {
        this.newList = newList;
        this.oldList = oldList;
    }

    @Override
    public int getOldListSize() {
        return oldList != null ? oldList.size() : 0;
    }

    @Override
    public int getNewListSize() {
        return newList != null ? newList.size() : 0;
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return newList.get(newItemPosition).getMacdev()==oldList.get(oldItemPosition).getMacdev() ;
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        int result = newList.get(newItemPosition).compareTo(oldList.get(oldItemPosition));
        return result == 0;
    }

    @Nullable
    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {

        RepeaterModel newModel = newList.get(newItemPosition);
        RepeaterModel oldModel = oldList.get(oldItemPosition);

        Bundle diff = new Bundle();
        if(newModel.getMacdev().equals(oldModel.getMacdev()) ) {
            if (newModel.rssi != (oldModel.rssi)) {
                diff.putInt("price", newModel.rssi);
            }
            if (diff.size() == 0) {
                return null;
            }
        }
        return diff;
        //return super.getChangePayload(oldItemPosition, newItemPosition);
    }
}

Lets say your adapter has a private field mItems and a public method that looks like this 假设您的适配器有一个私有字段mItems和一个公共方法,如下所示

public void setItems(List<YourClass> items){
    mItems= items;
    notifyDataSetChanged();
}

Calling this method would refresh your recycler view. 调用此方法将刷新您的回收站视图。 Alternatively, you can simply notify your adapter like this: 另外,您可以像这样简单地通知适配器:

yourAdapterInstance.notifyDataSetChanged();

The implementation of DiffCallback is not working correctly: DiffCallback的实现无法正常工作:

@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
    return newList.get(newItemPosition).getMacdev()==oldList.get(oldItemPosition).getMacdev() ;
}

to use equals method instead of '==' 使用equals方法而不是'=='

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return newList.get(newItemPosition).getMacdev().equals(oldList.get(oldItemPosition).getMacdev()) ;
    }

Also, remove this.notifyItemChanged(position); 另外,删除this.notifyItemChanged(position); from method public void onBindViewHolder(CryptoViewHolder holder, int position, List<Object> payloads) { also you need to update list before dispatching update. 来自方法public void onBindViewHolder(CryptoViewHolder holder, int position, List<Object> payloads) {另外,在分派更新之前,您也需要更新列表。

public void setData(ArrayList<RepeaterModel> newData) {

    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new 
    MyDiffUtilCallBack(newData, data));

    data.clear();
    this.data.addAll(newData);
    diffResult.dispatchUpdatesTo(this);
}

PS: the code may be not working correctly, changing the color to Color GREEN may affect "non updated" item du to recycling. PS:代码可能无法正常工作,将颜色更改为“绿色”可能会影响“未更新”的项目以便回收。 It is better to change the RepeaterModel by adding the edited/updated information to model. 最好通过将已编辑/更新的信息添加到模型来更改RepeaterModel。

You should set adapter ie recylerview.setAdapter(adapter) only once.And at any other place where you are changing the data in the Arraylist use adapter.notifyDatasetChanged() to refresh list. 您应该只设置一次adapterrecylerview.setAdapter(adapter)在要更改Arraylist数据的任何其他地方,请使用adapter.notifyDatasetChanged()刷新列表。 It will refresh only the changes not the whole list. 它将仅刷新更改,而不刷新整个列表。

Source: https://medium.com/@suragch/updating-data-in-an-android-recyclerview-842e56adbfd8 资料来源: https : //medium.com/@suragch/updating-data-in-an-android-recyclerview-842e56adbfd8

Instead of notifyDatasetChanged, you should use notifyItemChanged() with an customized object. 您应该将notifyItemChanged()与自定义对象一起使用,而不是notifyDatasetChanged。

Create data class say UpdateRecord with 2 members 创建具有2个成员的数据类,例如UpdateRecord

data class UpdateRecord(val _name : String? , val _rssi :String?)

when rssi changes, call Adapter's 当rssi更改时,请调用适配器的

notifyItemChange(position, UpdateRecord(null, newRssi))

You will receive call onBindViewHolder(position, payload), the first object in payload is the UpdateRecord object. 您将收到onBindViewHolder(position,payload)调用,有效负载中的第一个对象是UpdateRecord对象。 Check and do 检查并做

val updateRecord = payload[0] as UpdateRecord
if (updateRecord._name != null) {
  // update name text view
}
if (updateRecord._rssi != null) {
  // update rssi text view
}

This is the partial update mechanism in RecyclerView, which updates only what is changed. 这是RecyclerView中的部分更新机制,该机制仅更新更改的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM