为了账号安全,请及时绑定邮箱和手机立即绑定

Android RecyclerView中Adapter和ViewHolder的封装

标签:
Android

前情提要

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

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

具体实现

封装分为Adapter和ViewHolder两部分,如下所示.

ViewHolder

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

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

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

/**

 * 基础的ViewHolder

 * Created by zyz on 2016/5/17.

 */

public abstract class BaseHolder<m> 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 <t> View的类型

     * @return view

     */

    protected <t   extends="" view="">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);

}</t></t></m>

 

Adapter

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

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

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

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

[代码]java代码:

?

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

/**

 * 基础的Adapter

 * Created by zyz on 2016/5/17.

 */

public abstract class BaseAdapter<m, h="" extends=""   baseholder<m="">> extends RecyclerView.Adapter<h> {

  

    protected List<m>   dataList;

    protected OnItemClickListener<h>   listener;

  

    /**

     * 设置数据,并设置点击回调接口

     *

     * @param list 数据集合

     * @param listener 回调接口

     */

    public BaseAdapter(@Nullable List<m>   list, @Nullable OnItemClickListener<h> 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<m>   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<m>   list) {

        dataList.addAll(list);

    }

  

    /**

     * 在最顶部前置数据

     *

     * @param data 要前置的数据

     */

    public void preposeItem(M data)   {

        dataList.add(0,   data);

    }

  

    /**

     * 在顶部前置数据集合

     *

     * @param list 要前置的数据集合

     */

    public void preposeList(List<m>   list) {

        dataList.addAll(0,   list);

    }

}</m></m></m></h></m></h></m></h></m,>

 

使用范例

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

一种Item

运行结果如下图所示:


单个Item类型的ViewHolder如下:

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

/**

 * 一种View的Holder

 * Created by zyz on 2016/5/17.

 */

public class SingleHolder extends BaseHolder<person>   {

  

    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()));

    }

}</person>

 

与之对应的Adapter如下:

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

/**

 * 一种item的Adapter

 * Created by zyz on 2016/5/17.

 */

public class SingleAdapter extends BaseAdapter<person,   singleholder=""> {

  

    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<singleholder> {

  

        void onNameClick(String   name);

  

        void onAgeClick(int   age);

    }

}</singleholder></person,>

 

多种Item

运行结果如下图所示:


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

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

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

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

[代码]java代码:

?

1

2

3

4

5

6

7

8

9

Holder部分如下:

|-ChatHolder //聊天View的Holder,包含公共部分

    |-TextHolder //文字消息的Holder,包含文字特有的部分

    |-ImageHolder //图片消息的Holder,包含图片特有的部分.

  

数据部分如下:

|-ChatMsg //代表一条聊天消息

    |-TextMsg //代表一条文字消息

    |-ImageMsg //代表一条图片消息

 

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

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

/**

 * 聊天界面的ViewHolder

 * Created by zyz on 2016/5/18.

 */

public class ChatHolder extends BaseHolder<chatmsg>   {

  

    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());

    }

}</chatmsg>

 

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

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

/**

 * 文本消息的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

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

/**

 * 表情消息的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,代码不多.

```java
/**

·         聊天界面的Adapter

·         Created by zyz on 2016/5/18.
*/
public class ChatAdapter extends BaseAdapter<ChatMsg, ChatHolder> {

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;

原文链接:http://www.apkbus.com/blog-705730-61342.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消