博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
RecyclerView中Adapter和ViewHolder的封装
阅读量:6002 次
发布时间:2019-06-20

本文共 7950 字,大约阅读时间需要 26 分钟。

前情提要

最近项目我在项目中使用了RecyclerView代替了ListView.由于项目中有多出列表项使用RecyclerView,这就导致需要写多个AdapterViewHolder.

其实,怎么说呢?就是懒,想少写代码,所以想研究一下能否简化一下.

具体实现

封装分为AdapterViewHolder两部分,如下所示.

ViewHolder

抽象类BaseHolder继承RecyclerView.ViewHolder,并依赖注入的数据类型M,即和ViewHolder绑定的数据类型为M.

该抽象类包含一个构造方法,用于获取item对应的布局.一个抽象函数用于将数据设置到item上面.

/** * 基础的ViewHolder * Created by zyz on 2016/5/17. */public abstract class BaseHolder
extends RecyclerView.ViewHolder { public BaseHolder(ViewGroup parent, @LayoutRes int resId) { super(LayoutInflater.from(parent.getContext()).inflate(resId, parent, false)); } /** * 获取布局中的View * @param viewId view的Id * @param
View的类型 * @return view */ protected
T getView(@IdRes int viewId){ return (T) (itemView.findViewById(viewId)); } /** * 获取Context实例 * @return context */ protected Context getContext() { return itemView.getContext(); } /** * 设置数据 * @param data 要显示的数据对象 */ public abstract void setData(M data);}

Adapter

Adapter类也为抽象类,继承于RecyclerView.Adapter,并绑定了两个泛型:

  1. M : 用于该 Adapter 的列表的数据类型,即List<M>.

  2. H : 即和 Adapter 绑定的 Holder 的类型.

并且,该 Adapter 自带 List 数据集合,声明时可以不用传递数据集合.也包含了 List 的相关操作.同时还给该 Adapter 绑定了一个 item 的点击事件,且为可选操作,不需要点击操作,直接传null即可.

/** * 基础的Adapter * Created by zyz on 2016/5/17. */public abstract class BaseAdapter
> extends RecyclerView.Adapter
{ protected List
dataList; protected OnItemClickListener
listener; /** * 设置数据,并设置点击回调接口 * * @param list 数据集合 * @param listener 回调接口 */ public BaseAdapter(@Nullable List
list, @Nullable OnItemClickListener
listener) { this.dataList = list; if (this.dataList == null) { this.dataList = new ArrayList<>(); } this.listener = listener; } @Override public void onBindViewHolder(final H holder, int position) { holder.setData(dataList.get(position)); if (listener != null) { holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { listener.onItemClick(holder); } }); } } @Override public int getItemCount() { return dataList.size(); } /** * 填充数据,此方法会清空以前的数据 * * @param list 需要显示的数据 */ public void fillList(List
list) { dataList.clear(); dataList.addAll(list); } /** * 更新数据 * * @param holder item对应的holder * @param data item的数据 */ public void updateItem(H holder, M data) { dataList.set(holder.getLayoutPosition(), data); } /** * 获取一条数据 * * @param holder item对应的holder * @return 该item对应的数据 */ public M getItem(H holder) { return dataList.get(holder.getLayoutPosition()); } /** * 获取一条数据 * * @param position item的位置 * @return item对应的数据 */ public M getItem(int position) { return dataList.get(position); } /** * 追加一条数据 * * @param data 追加的数据 */ public void appendItem(M data) { dataList.add(data); } /** * 追加一个集合数据 * * @param list 要追加的数据集合 */ public void appendList(List
list) { dataList.addAll(list); } /** * 在最顶部前置数据 * * @param data 要前置的数据 */ public void preposeItem(M data) { dataList.add(0, data); } /** * 在顶部前置数据集合 * * @param list 要前置的数据集合 */ public void preposeList(List
list) { dataList.addAll(0, list); }}

使用范例

使用范例为一种Item和多种Item这两种类型.

一种Item

运行结果如下图所示:

单个Item类型的ViewHolder如下:

/** * 一种View的Holder * Created by zyz on 2016/5/17. */public class SingleHolder extends BaseHolder
{ TextView nameView; TextView ageView; public SingleHolder(ViewGroup parent, @LayoutRes int resId) { super(parent, resId); nameView = getView(R.id.name_tv); ageView = getView(R.id.age_tv); } @Override public void setData(Person data) { nameView.setText(data.getName()); ageView.setText(String.valueOf(data.getAge())); }}

与之对应的Adapter如下:

/** * 一种item的Adapter * Created by zyz on 2016/5/17. */public class SingleAdapter extends BaseAdapter
{ public SingleAdapter(SingleItemClickListener listener) { super(null, listener); } @Override public SingleHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new SingleHolder(parent, R.layout.item_single); } @Override public void onBindViewHolder(final SingleHolder holder, int position) { super.onBindViewHolder(holder, position); holder.nameView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ((SingleItemClickListener) listener).onNameClick(getItem(holder).getName()); } }); holder.ageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ((SingleItemClickListener) listener).onAgeClick(getItem(holder).getAge()); } }); } public interface SingleItemClickListener extends OnItemClickListener
{ void onNameClick(String name); void onAgeClick(int age); }}

多种Item

运行结果如下图所示:

多个Item的ViewHolder的写法,可以根据Item的View重合度来写:

  1. 如果多个item完全没有相同的部分,则单独继承ViewHolder

  2. 如果Item之间有相同的部分,可以抽出来一个父类来继承ViewHolder

这里的范例Item是具有重合部分的.模型来自聊天界面.

Holder部分如下:|-ChatHolder //聊天View的Holder,包含公共部分    |-TextHolder //文字消息的Holder,包含文字特有的部分    |-ImageHolder //图片消息的Holder,包含图片特有的部分.    数据部分如下:|-ChatMsg //代表一条聊天消息    |-TextMsg //代表一条文字消息    |-ImageMsg //代表一条图片消息

ChatHolder代码如下,包含发送者的名称和时间:

/** * 聊天界面的ViewHolder * Created by zyz on 2016/5/18. */public class ChatHolder extends BaseHolder
{ TextView senderNameTv; TextView createTimeTv; public ChatHolder(ViewGroup parent, @LayoutRes int resId) { super(parent, resId); senderNameTv = getView(R.id.name_tv); createTimeTv = getView(R.id.create_time_tv); } @Override public void setData(ChatMsg data) { senderNameTv.setText(data.getSenderName()); createTimeTv.setText(data.getCreateTime()); }}

TextHolder的代码如下,包含文本显示的View

/** * 文本消息的Holder * Created by zyz on 2016/5/18. */public class TextHolder extends ChatHolder {    TextView contentTv;    public TextHolder(ViewGroup parent, @LayoutRes int resId) {        super(parent, resId);        contentTv = getView(R.id.content_tv);    }    @Override    public void setData(ChatMsg data) {        super.setData(data);        contentTv.setText(((TextMsg)data).getText());    }}

其中的setData()方法默认调用父类的方法,可以直接设置发送者的名称和时间.

ImageHolder的代码如下,包含显示图片的View

/** * 表情消息的Holder * Created by zyz on 2016/5/18. */public class ImageHolder extends ChatHolder {    ImageView contentIv;    public ImageHolder(ViewGroup parent, @LayoutRes int resId) {        super(parent, resId);        contentIv = getView(R.id.content_iv);    }    @Override    public void setData(ChatMsg data) {        super.setData(data);        contentIv.setImageResource(((ImageMsg)data).getResId());    }}

最后是我们的Adapter,代码不多.

/** * 聊天界面的Adapter * Created by zyz on 2016/5/18. */public class ChatAdapter extends BaseAdapter
{ private static final int VIEW_TEXT = 0; private static final int VIEW_IMAGE = 1; public ChatAdapter(OnItemClickListener
listener) { super(null, listener); } @Override public ChatHolder onCreateViewHolder(ViewGroup parent, int viewType) { ChatHolder holder; if (viewType == VIEW_IMAGE) { holder = new ImageHolder(parent, R.layout.item_msg_img_left); } else { holder = new TextHolder(parent, R.layout.item_msg_text_left); } return holder; } @Override public int getItemViewType(int position) { if (getItem(position).getMsgType() == ChatMsg.TYPE_TEXT) { return VIEW_TEXT; } else { return VIEW_IMAGE; } }}

上述设置的有时间监听,则对应的事件处理在Activity中完成

chatAdapter = new ChatAdapter(new OnItemClickListener
() { @Override public void onItemClick(ChatHolder holder) { //处理事件 }});

以上就是对ViewHolder和Adapter的简易封装,以后会根据需要继续封装简化.

代码地址如下:

更多文章请移步我的博客:

重要说明

想随时获取最新博客文章更新,请关注公共账号DevWiki,或扫描下面的二维码:

微信公共号

转载地址:http://hldmx.baihongyu.com/

你可能感兴趣的文章
SVN客户端使用教程
查看>>
Windows 8 应用开发权威指南 之 应用程序的数据存储(1)应用程序安装目录操作...
查看>>
节点指向c语言新建双循环链表/遍历
查看>>
MVC 模型绑定
查看>>
视频教程视频Java+PHP+.NET海量教程来了 500G教程
查看>>
字符搜索正则表达式语法详解
查看>>
条件数据库Android:sqllite使用
查看>>
回溯法---->哈密顿环
查看>>
Javascript 连连看
查看>>
智能手机中显示信号强度格数
查看>>
Wcf服务引用报错数据包含无法解析的引用:没有终结点在侦听可以接受消息的 这通常是由于不正确的地址或者 SOAP 操作导致的...
查看>>
“内心强大"
查看>>
jsp自定义标签技术(原理和代码实现以及平台搭建)
查看>>
分析:重定向和请求转发
查看>>
java向上转型和向下转型
查看>>
正则表达式应用实例
查看>>
分享:2013中国开发者大会(移动和游戏)--广州站
查看>>
ra寄存器定位core
查看>>
PL/pgSQL多输出参数例子
查看>>
Android--UI之Spinner
查看>>