ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android RecyclerView

2021-04-26 21:01:20  阅读:172  来源: 互联网

标签:dataItem int value public content Android RecyclerView id


RecyclerView 常规使用

DataItem.java

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

  • 可选实现 Cloneable 接口,可解决后面遇到对象引用问题

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 刷新

  • 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 刷新

  • Item 的部分 View 控件刷新
//修改指定 position 上 Item 局部 View 的刷新,
mAdapter.notifyItemChanged(int position,Object payload)
//修改从 positionStart 开始到 itemCount 数量的 Item 局部 View 的刷新
mAdapter.notifyItemRangeChanged(int positionStart, int itemCount,Object payload)
  • 假设 payload 只传 【key 标记】的话,刷新前的数据源就需要修改完毕,这样 Adapter 才直接用数据源
  • 另外 payload 可以传 【key-value 键值对】,比如 Map ,那么 Adapter 可以不用数据源而改用 value

修改 DataItemRVAdapter

  • 覆写带 Payload 参数的 onBindViewHolder 方法
 @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 刷新

  • 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);
}
  • 能够保留了 item 动画

2 局部刷新 View 刷新

  • Item 的部分 View 控件刷新

  • 同上,Adapter 需要覆写带 Payload 参数的 onBindViewHolder 方法

修改 DiffUtilCallback

  • 覆写 getChangePayload 方法
    @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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有