ITPub博客

首页 > IT职业 > IT职场 > Android RecyclerView的ViewHolder和Ada

Android RecyclerView的ViewHolder和Ada

IT职场 作者:fondtiger 时间:2021-09-09 09:59:47 0 删除 编辑

前一段时间,因为项目需要使用了RecyclerView,为了方便使用还进行封装了,详细参见此处:RecyclerView中Adapter和ViewHolder的封装 - DevWiki。

那样的封装有几个问题:

1.   ViewHolder的setData(M data)虽然方便设置数据,但是ViewHolder需要知晓数据类型。ViewHolder应该只用作View的缓存,而不应该知晓填充View的数据。

2.   BaseAdapter无法添加Header和Footer。

3.   点击事件耦合性较高。

基于以上几点,对BaseHolder和BaseAdapter进行修改优化。

BaseHolder的优化

相对于旧版的BaseHolder:

1.   新版的去除的数据类型的注入,使ViewHolder只用来缓存View。

2.   添加SparseArray,使之来缓存View。

3.   添加BaseHolder(View view)构造器,外部更方便控制View。

4.   保留getContext()方法,方便获取Context对象。

新版的BaseHolder代码如下:

[代码]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

41

42

43

44

45

46

47

48

49

50

51

public class BaseHolder extends RecyclerView.ViewHolder   {

  

    private SparseArray viewArray;

  

    

    public BaseHolder(ViewGroup   parent, @LayoutRes int resId) {

        super(LayoutInflater.from(parent.getContext()).inflate(resId,   parent, false));

        viewArray   = new SparseArray();

    }

  

    

    public BaseHolder(View view) {

        super(view);

        viewArray   = new SparseArray();

    }

  

    

    protected T getView(@IdRes int viewId){

        View   view = viewArray.get(viewId);

        if (view   == null) {

            view   = itemView.findViewById(viewId);

            viewArray.put(viewId,   view);

        }

        return (T)   view;

    }

  

    

    protected Context getContext()   {

        return itemView.getContext();

    }

}

 

Adapter部分的优化

Adapter拆分为两个抽象类:AbsAdapter与BaseAdapter,其中:
AbsAdapter:封装了和ViewHolder和HeaderView,FooterView相关的方法。
BaseAdapter:继承AbsAdapter,封装了数据相关的方法。

各自聚焦于不同的方面,方面日后扩展。

AbsAdapter的代码如下:

[代码]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

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

  

public abstract class AbsAdapter extends RecyclerView.Adapter {

  

    private static final String TAG   = "AbsAdapter";

  

    public static final int VIEW_TYPE_HEADER   = 1024;

    public static final int VIEW_TYPE_FOOTER   = 1025;

  

    protected View headerView;

    protected View footerView;

  

    protected Context context;

  

    public AbsAdapter(Context   context) {

        this.context   = context;

    }

  

    @Override

    public final BaseHolder   onCreateViewHolder(ViewGroup parent, int viewType) {

        if (viewType   == VIEW_TYPE_HEADER) {

            return   new BaseHolder(headerView);

        } else if   (viewType == VIEW_TYPE_FOOTER) {

            return   new BaseHolder(footerView);

        } else {

            return   createCustomViewHolder(parent, viewType);

        }

    }

  

    

    public abstract VH   createCustomViewHolder(ViewGroup parent, int viewType);

  

    @Override

    public final void onBindViewHolder(BaseHolder   holder, int position) {

        switch (holder.getItemViewType())   {

            case   VIEW_TYPE_HEADER:

            case   VIEW_TYPE_FOOTER:

                break;

            default:

                bindCustomViewHolder((VH)   holder, position);

                break;

        }

    }

  

    

    public abstract void bindCustomViewHolder(VH   holder, int position);

  

    

    public void addHeaderView(View   headerView) {

        if (headerView   == null) {

            Log.w(TAG,   "add the header view is null");

            return   ;

        }

        this.headerView   = headerView;

        notifyDataSetChanged();

    }

  

    

    public void removeHeaderView()   {

        if (headerView   != null) {

            headerView   = null;

            notifyDataSetChanged();

        }

    }

  

    

    public void addFooterView(View   footerView) {

        if (footerView   == null) {

            Log.w(TAG,   "add the footer view is null");

            return;

        }

        this.footerView   = footerView;

        notifyDataSetChanged();

    }

  

    

    public void removeFooterView()   {

        if (footerView   != null) {

            footerView   = null;

            notifyDataSetChanged();

        }

    }

  

    

    public int getExtraViewCount()   {

        int extraViewCount   = 0;

        if (headerView   != null) {

            extraViewCount++;

        }

        if (footerView   != null) {

            extraViewCount++;

        }

        return extraViewCount;

    }

  

    

    public int getHeaderExtraViewCount()   {

        return headerView   == null ? 0 : 1;

    }

  

    

    public int getFooterExtraViewCount()   {

        return footerView   == null ? 0 : 1;

    }

  

    @Override

    public abstract long getItemId(int   position);

},>

 

BaseAdapter的代码如下:

[代码]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

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

  

public abstract class BaseAdapter extends AbsAdapter {

  

    private List dataList;

  

    public BaseAdapter(Context   context) {

        super(context);

        this.dataList   = new ArrayList();

    }

  

    public BaseAdapter(Context   context, List list) {

        super(context);

        this.dataList   = new ArrayList();

        this.dataList.addAll(list);

    }

  

    

    public boolean fillList(List   list) {

        dataList.clear();

        boolean   result = dataList.addAll(list);

        if (result)   {

            notifyDataSetChanged();

        }

        return result;

    }

  

    

    public boolean appendItem(M   data) {

        boolean   result = dataList.add(data);

        if (result)   {

            if   (getHeaderExtraViewCount() == 0) {

                notifyItemInserted(dataList.size()   - 1);

            }   else {

                notifyItemInserted(dataList.size());

            }

        }

        return result;

    }

  

    

    public boolean appendList(List   list) {

        boolean   result = dataList.addAll(list);

        if (result)   {

            notifyDataSetChanged();

        }

        return result;

    }

  

    

    public void proposeItem(M data)   {

        dataList.add(0,   data);

        if (getHeaderExtraViewCount()   == 0) {

            notifyItemInserted(0);

        } else {

            notifyItemInserted(getHeaderExtraViewCount());

        }

    }

  

    

    public void proposeList(List   list) {

        dataList.addAll(0,   list);

        notifyDataSetChanged();

    }

  

    @Override

    public long getItemId(int position)   {

        return position;

    }

  

    @Override

    public final int getItemViewType(int   position) {

        if (headerView   != null && position == 0) {

            return   VIEW_TYPE_HEADER;

        } else if   (footerView != null && position == dataList.size() +   getHeaderExtraViewCount()) {

            return   VIEW_TYPE_FOOTER;

        } else {

            return   getCustomViewType(position);

        }

    }

  

    

    public abstract int getCustomViewType(int   position);

  

    @Override

    public int getItemCount() {

        return dataList.size()   + getExtraViewCount();

    }

  

    

    public M getItem(int position)   {

        if (headerView   != null && position == 0

                ||   position >= dataList.size() + getHeaderExtraViewCount()) {

            return   null;

        }

        return headerView   == null ? dataList.get(position) : dataList.get(position - 1);

    }

  

    

    public M getItem(VH holder) {

        return getItem(holder.getAdapterPosition());

    }

  

    public void updateItem(M data)   {

        int index   = dataList.indexOf(data);

        if (index  

            return;

        }

        dataList.set(index,   data);

        if (headerView   == null) {

            notifyItemChanged(index);

        } else {

            notifyItemChanged(index   + 1);

        }

    }

  

    

    public void removeItem(int position)   {

        if (headerView   == null) {

            dataList.remove(position);

        } else {

            dataList.remove(position   - 1);

        }

        notifyItemRemoved(position);

    }

  

    

    public void removeItem(M data)   {

        int index   = dataList.indexOf(data);

        if (index  

            return;

        }

        dataList.remove(index);

        if (headerView   == null) {

            notifyItemRemoved(index);

        } else {

            notifyItemRemoved(index   + 1);

        }

    }

},>,>

 

点击事件的优化

为了降低点击事件的耦合性,将点击事件从Adapter中移除,使用另外一种方式来实现。使用代码如下:

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(recyclerView,

        new RecyclerItemClickListener.OnItemClickListener()   {

            @Override

            public   void onItemClick(View view, int position) {

                Person   person = singleAdapter.getItem(position);

                Toast.makeText(SingleActivity.this,   "click:" + person,

                        Toast.LENGTH_SHORT).show();

            }

  

            @Override

            public   void onItemLongClick(View view, int position) {

                Person   person = singleAdapter.getItem(position);

                Toast.makeText(SingleActivity.this,   "Long Click:" + person,

                        Toast.LENGTH_SHORT).show();

            }

        }));

 

使用RecyclerView的自带的方法addOnItemTouchListener()实现点击和长点击事件。实现代码如下:

[代码]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

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

  

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener   {

  

    private OnItemClickListener   clickListener;

    private GestureDetector   gestureDetector;

  

    public interface OnItemClickListener   {

        

        void onItemClick(View   view, int position);

  

        

        void onItemLongClick(View   view, int position);

    }

  

    public RecyclerItemClickListener(final   RecyclerView recyclerView,

                                     OnItemClickListener   listener) {

        this.clickListener   = listener;

        gestureDetector   = new GestureDetector(recyclerView.getContext(),

                new   GestureDetector.SimpleOnGestureListener() {

                    @Override

                    public   boolean onSingleTapUp(MotionEvent e) {

                        return   true;

                    }

  

                    @Override

                    public   void onLongPress(MotionEvent e) {

                        View   childView = recyclerView.findChildViewUnder(e.getX(), e.getY());

                        if   (childView != null && clickListener != null) {

                            clickListener.onItemLongClick(childView,

                                    recyclerView.getChildAdapterPosition(childView));

                        }

                    }

                });

    }

  

    @Override

    public boolean onInterceptTouchEvent(RecyclerView   rv, MotionEvent e) {

        View   childView = rv.findChildViewUnder(e.getX(), e.getY());

        if (childView   != null && clickListener != null &&   gestureDetector.onTouchEvent(e)) {

            clickListener.onItemClick(childView,   rv.getChildAdapterPosition(childView));

            return   true;

        }

        return false;

    }

  

    @Override

    public void onTouchEvent(RecyclerView   rv, MotionEvent e) {

  

    }

  

    @Override

    public void onRequestDisallowInterceptTouchEvent(boolean   disallowIntercept) {

  

    }

}

 

分割线的优化

RecyclerView的分割线不像ListView那样方便,但是RecyclerView也提供了``方法来添加分割线。

分割线代码使用的是SDK中的Sample的代码,在其中添加了``方法,方便设置分割线的形式。

具体的代码参见此处:DividerDecoration.java

优化后的使用

优化后使用方式有所改变,具体使用方式如下:

[代码]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

recyclerView = (RecyclerView)   findViewById(R.id.single_rv);

layoutManager = new LinearLayoutManager(this);

recyclerView.setLayoutManager(layoutManager);

DividerDecoration decoration = new DividerDecoration(this,   DividerDecoration.VERTICAL_LIST);

Drawable drawable =   getResources().getDrawable(R.drawable.divider_single);

decoration.setDivider(drawable);

recyclerView.addItemDecoration(decoration);

recyclerView.setAdapter(singleAdapter);

  

View view =   LayoutInflater.from(this).inflate(R.layout.item_single_header, null, false);

singleAdapter.addHeaderView(view);

  

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(recyclerView,

        new RecyclerItemClickListener.OnItemClickListener()   {

            @Override

            public   void onItemClick(View view, int position) {

                Person   person = singleAdapter.getItem(position);

                Toast.makeText(SingleActivity.this,   "click:" + person,

                        Toast.LENGTH_SHORT).show();

            }

  

            @Override

            public   void onItemLongClick(View view, int position) {

                Person   person = singleAdapter.getItem(position);

                Toast.makeText(SingleActivity.this,   "Long Click:" + person,

                        Toast.LENGTH_SHORT).show();

            }

        }));

 

以上所有的代码均在GitHub上,具体地址在此:Dev-Wiki/RecyclerView

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

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/2508/viewspace-2814823/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: jstl 写的分页
请登录后发表评论 登录
全部评论

注册时间:2019-09-29

  • 博文量
    122
  • 访问量
    13451