其他分享
首页 > 其他分享> > Android RecyclerView

Android RecyclerView

作者:互联网

RecyclerView 常规使用

DataItem.java

public class DataItem {
    public String id;
    public String title;
    public String subtitle;
    public String content;
    public int imageResId;
}

listitem_image_text.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">


    <TextView
        android:id="@+id/id_tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:padding="10dp"
        android:singleLine="true"
        android:textSize="22sp"
        app:layout_constraintEnd_toStartOf="@id/id_iv"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="标题标题标题标题标题标题标题标题标题标题end" />

    <TextView
        android:id="@+id/id_tv_subtitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:padding="10dp"
        android:singleLine="true"
        android:textSize="18sp"
        app:layout_constraintEnd_toStartOf="@id/id_iv"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/id_tv_title"
        tools:text="副标题副标题副标题副标题副标题副标题副标题副标题副标题副标题副标题end" />

    <TextView
        android:id="@+id/id_tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:textSize="14sp"
        app:layout_constraintEnd_toStartOf="@id/id_iv"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/id_tv_subtitle"
        tools:text="内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容end" />

    <!--在 id_tv_title,id_tv_subtitle,id_tv_content 三个控件右侧设置一道屏障-->
    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/id_barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="right"
        app:constraint_referenced_ids="id_tv_title,id_tv_subtitle,id_tv_content" />

    <!--id_iv 控件依赖上面这道屏障-->
    <ImageView
        android:id="@+id/id_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/id_barrier" />


</androidx.constraintlayout.widget.ConstraintLayout>

DataItemViewHolder.java

public class DataItemViewHolder extends RecyclerView.ViewHolder {
    TextView id_tv_title;
    TextView id_tv_subtitle;
    TextView id_tv_content;
    ImageView id_iv;

    public DataItemViewHolder(@NonNull View itemView) {
        super(itemView);
        id_tv_title = itemView.findViewById(R.id.id_tv_title);
        id_tv_subtitle = itemView.findViewById(R.id.id_tv_subtitle);
        id_tv_content = itemView.findViewById(R.id.id_tv_content);
        id_iv = itemView.findViewById(R.id.id_iv);
    }

}

DataItemRVAdapter.java

public class DataItemRVAdapter extends RecyclerView.Adapter<DataItemViewHolder> {
    public static final String KEY_TITLE = "KEY_TITLE";
    public static final String KEY_SUBTITLE = "KEY_SUBTITLE";
    public static final String KEY_CONTENT = "KEY_CONTENT";
    public static final String KEY_IMAGE = "KEY_IMAGE";

    private List<DataItem> mDataItemList;

    public void setDataItemList(List<DataItem> dataItemList) {
        this.mDataItemList = new ArrayList<>(dataItemList);
        /*this.mDataItemList = new ArrayList<>();
        this.mDataItemList.addAll(dataItemList);*/
    }

    public List<DataItem> getDataItemList() {
        return mDataItemList;
    }

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

    @Override
    public void onBindViewHolder(@NonNull DataItemViewHolder holder, int position) {
        DataItem dataItem = mDataItemList.get(position);
        holder.id_tv_title.setText(dataItem.title);
        holder.id_tv_subtitle.setText(dataItem.subtitle);
        holder.id_tv_content.setText(dataItem.content);
        holder.id_iv.setImageResource(dataItem.imageResId);
    }

    @Override
    public void onBindViewHolder(@NonNull DataItemViewHolder holder, int position, @NonNull List<Object> payloads) {
        if (payloads.isEmpty()) {
            //【列表刷新】 或者 【列表局部 Item 刷新】
            super.onBindViewHolder(holder, position, payloads);
        } else {
            //【Item 局部 View 刷新】
            Object payload = payloads.get(0);
            if (payload instanceof Map) {
                //【key-value 键值对】
                Map<String, String> map = (Map<String, String>) payload;
                for (Map.Entry<String, String> stringObjectEntry : map.entrySet()) {
                    String key = stringObjectEntry.getKey();
                    String value = stringObjectEntry.getValue();
                    //简单封装
                    bindViewHolder(holder, position, key, value);
                }
            } else if (payload instanceof String) {
                //【key 标记】
                String key = (String) payload;
                //简单封装
                bindViewHolder(holder, position, key, null);
            }

        }
    }

    private void bindViewHolder(DataItemViewHolder holder, int position, String key, String value) {
        DataItem dataItem = mDataItemList.get(position);
        if (key.equals(KEY_TITLE)) {
            holder.id_tv_title.setText(value != null ? value : dataItem.title);
        } else if (key.equals(KEY_SUBTITLE)) {
            holder.id_tv_subtitle.setText(value != null ? value : dataItem.content);
        } else if (key.equals(KEY_CONTENT)) {
            holder.id_tv_content.setText(value != null ? value : dataItem.content);
        } else if (key.equals(KEY_IMAGE)) {
            holder.id_iv.setImageResource(value != null ? Integer.parseInt(value) : dataItem.imageResId);
        }
    }

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

}

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private List<DataItem> mDataItemList;
    private DataItemRVAdapter mDataItemRVAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button id_btn = findViewById(R.id.id_btn);

        id_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //
                refreshData();
            }
        });
        //
        initData();
        //
        RecyclerView id_rv = findViewById(R.id.id_rv);
        id_rv.setLayoutManager(new LinearLayoutManager(this));
        id_rv.setItemAnimator(new DefaultItemAnimator());
        mDataItemRVAdapter = new DataItemRVAdapter();
        //初始化
        id_rv.setAdapter(mDataItemRVAdapter);
        mDataItemRVAdapter.setDataItemList(mDataItemList);
    }

    private void initData() {
        mDataItemList = new ArrayList<>();
        for (int i = 0; i < 15; i++) {
            DataItem dataItem = new DataItem();
            dataItem.id = String.valueOf(i + 1);
            dataItem.title = dataItem.id + " title";
            dataItem.subtitle = dataItem.id + " subtitle";
            dataItem.content = dataItem.id + " content";
            dataItem.imageResId = R.mipmap.ic_launcher;
            mDataItemList.add(dataItem);
        }

    }

    private void refreshData() {
        //mDataItemList 存放最新的数据
        //1 修改数据
        //引用传递,会影响 Adapter 里 list(虽然 Adapter 里 list 已经是 new ArrayList 了)对应索引的对象的值,但是因为这里不影响
        mDataItemList.get(1).title = "222 title new";
        mDataItemList.get(1).subtitle = "222 subtitle new";
        mDataItemList.get(1).content = "222 content new";
        //2 更新 Adapter 数据源
        mDataItemRVAdapter.setDataItemList(mDataItemList);
        //3 通过 Adapter#notifyDataSetChanged 方式通知数据刷新
        mDataItemRVAdapter.notifyDataSetChanged();

    }
}

1 全局刷新

//列表可见部分全部刷新
mAdapter.notifyDataSetChanged()

2 局部刷新 Item 刷新

//修改指定 position 上 Item 的刷新
mAdapter.notifyItemChanged(int position)
//添加指定 position 上 Item 的刷新
mAdapter.notifyItemInserted(int position)
//移除指定 position 上 Item 的刷新
mAdapter.notifyItemRemoved(int position)
//修改从 positionStart 开始到 itemCount 数量的 Item 的刷新
mAdapter.notifyItemRangeChanged(int positionStart, int itemCount)
//添加从 positionStart 开始到 itemCount 数量的 Item 的刷新
mAdapter.notifyItemRangeInserted(int positionStart, int itemCount)
//移除从 positionStart 开始到 itemCount 数量的 Item 的刷新
mAdapter.notifyItemRangeRemoved(int positionStart, int itemCount)

//移到指定 fromPosition 到 toPosition 上 Item 的刷新
mAdapter.notifyItemMoved(int fromPosition, int toPosition)

3 局部刷新 View 刷新

//修改指定 position 上 Item 局部 View 的刷新,
mAdapter.notifyItemChanged(int position,Object payload)
//修改从 positionStart 开始到 itemCount 数量的 Item 局部 View 的刷新
mAdapter.notifyItemRangeChanged(int positionStart, int itemCount,Object payload)

修改 DataItemRVAdapter

 @Override
    public void onBindViewHolder(@NonNull DataItemViewHolder holder, int position, @NonNull List<Object> payloads) {
        if (payloads.isEmpty()) {
            //【列表刷新】 或者 【列表局部 Item 刷新】
            super.onBindViewHolder(holder, position, payloads);
        } else {
            //【Item 局部 View 刷新】
            Object payload = payloads.get(0);
            if (payload instanceof Map) {
                //【key-value 键值对】
                Map<String, String> map = (Map<String, String>) payload;
                for (Map.Entry<String, String> stringObjectEntry : map.entrySet()) {
                    String key = stringObjectEntry.getKey();
                    String value = stringObjectEntry.getValue();
                    //简单封装
                    bindViewHolder(holder, position, key, value);
                }
            } else if (payload instanceof String) {
                //【key 标记】
                String key = (String) payload;
                //简单封装
                bindViewHolder(holder, position, key, null);
            }

        }
    }

    private void bindViewHolder(DataItemViewHolder holder, int position, String key, String value) {
        DataItem dataItem = mDataItemList.get(position);
        if (key.equals(KEY_TITLE)) {
            holder.id_tv_title.setText(value != null ? value : dataItem.title);
        } else if (key.equals(KEY_SUBTITLE)) {
            holder.id_tv_subtitle.setText(value != null ? value : dataItem.content);
        } else if (key.equals(KEY_CONTENT)) {
            holder.id_tv_content.setText(value != null ? value : dataItem.content);
        } else if (key.equals(KEY_IMAGE)) {
            holder.id_iv.setImageResource(value != null ? Integer.parseInt(value) : dataItem.imageResId);
        }
    }

使用 DiffUtil 刷新数据

1 局部刷新 Item 刷新

创建 DiffUtilCallback

public class DiffUtilCallback extends DiffUtil.Callback {
    private List<DataItem> mOldDataItemList;
    private List<DataItem> mNewDataItemList;

    public DiffCallback(List<DataItem> oldDataItemList, List<DataItem> newDataItemList) {
        this.mOldDataItemList = oldDataItemList;
        this.mNewDataItemList = newDataItemList;
    }

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

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

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        //判断是不是同一个 item 的逻辑
        DataItem oldDataItem = mOldDataItemList.get(oldItemPosition);
        DataItem newDataItem = mNewDataItemList.get(newItemPosition);
        return Objects.equals(oldDataItem.id, newDataItem.id);
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        //areItemsTheSame 返回 true 的情况下走这个方法,进一步判断这个 item 的内容是否有变化
        DataItem oldDataItem = mOldDataItemList.get(oldItemPosition);
        DataItem newDataItem = mNewDataItemList.get(newItemPosition);
        // id
        if (!Objects.equals(oldDataItem.id, newDataItem.id)) {
            return false;
        }
        // name
        if (!Objects.equals(oldDataItem.name, newDataItem.name)) {
            return false;
        }
        // content
        if (!Objects.equals(oldDataItem.content, newDataItem.content)) {
            return false;
        }
        //如果还有,继续写其他判断条件

        //默认返回内容相等
        return true;
    }
}

修改 MainActivity 使用

private void refreshDataByDiffUtil() {
        List<DataItem> oldDataItemList = new ArrayList<>(mDataItemRVAdapter.getDataItemList());
        //mDataItemList 存放最新的数据
        //1 修改数据
        //别这么写!!!引用传递 引用传递会导致 calculateDiff 失效
//        mDataItemList.get(1).name = "222 new";
        DataItem oldDataItem = mDataItemList.get(2);
        DataItem newDataItem = new DataItem();
        newDataItem.id = oldDataItem.id;
        newDataItem.name = "333 new";//就改一个字段
        newDataItem.content = oldDataItem.content;
        mDataItemList.set(2, newDataItem);
        //2 更新 Adapter 数据源
        mDataItemRVAdapter.setDataItemList(mDataItemList);
        //3 DiffUtil 方式通知刷新
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallback(oldDataItemList, mDataItemList));
        //内部最终就是调用 Adapter#notifyItemXXX 系列方法实现的
        diffResult.dispatchUpdatesTo(mDataItemRVAdapter);
}

2 局部刷新 View 刷新

修改 DiffUtilCallback

    @Nullable
    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {
        DataItem oldDataItem = mOldDataItemList.get(oldItemPosition);
        DataItem newDataItem = mNewDataItemList.get(newItemPosition);
//        areItemsTheSame 返回 true 并且 areContentsTheSame 返回 false 的情况才会进来
        Map<String, String> payloadMap = new HashMap<>();
        // title
        if (!Objects.equals(oldDataItem.title, newDataItem.title)) {
            payloadMap.put(DataItemRVAdapter.KEY_TITLE, newDataItem.title);
        }
        // title
        if (!Objects.equals(oldDataItem.subtitle, newDataItem.subtitle)) {
            payloadMap.put(DataItemRVAdapter.KEY_SUBTITLE, newDataItem.subtitle);
        }
        // content
        if (!Objects.equals(oldDataItem.content, newDataItem.content)) {
            payloadMap.put(DataItemRVAdapter.KEY_CONTENT, newDataItem.content);
        }
        // imageResId
        if (oldDataItem.imageResId != newDataItem.imageResId) {
            payloadMap.put(DataItemRVAdapter.KEY_IMAGE, String.valueOf(newDataItem.imageResId));
        }
        if (!payloadMap.isEmpty()) {
            return payloadMap;
        }
        //默认无变化,内部传的是 null
        return super.getChangePayload(oldItemPosition, newItemPosition);
    }

使用

标签:dataItem,int,value,public,content,Android,RecyclerView,id
来源: https://blog.csdn.net/louisgeek/article/details/116172277