前言
目前的项目开发来看,列表依旧是整个APP内最主要的控件,而说到列表就会想到ListView,但ListView不仅优化不好,而且已经被新版Api中RecycleView所取代。所以今天来用RecycleView来设计Adapter的使用。
准备
引入RecycleView
如果我们想在项目中引用RecycleView,那我们首先得先添加V7包中的RecycleView,方法如下1
implementation 'com.android.support:recyclerview-v7:28.0.0'
创建一个Bean类
因为这个Demo中,需要一个Bean来存储数据,先把这些琐碎的工作做完,才好更好的开展。结构很简单,如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class Data {
private String title;
private String content;
public Data(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
Application
因为这个Demo中,我需要在整个项目中使用数据源,所以把数据源写到Application中吧,省着在主要代码中来上一段ArrayList的初始化赋值,有点违和。
定义条目布局
先来写老方式的Adapter
1 | public class OldAdapter extends RecyclerView.Adapter<OldAdapter.MyViewHolder> { |
实现思路:先定义一个ViewHolder用来做页面的缓存,由于我这个Item布局定义的很简单,所以同理,都是在ViewHolder中find到控件的id,然后初始化。最后在onBindViewHolder()中进行控件和数据的绑定。
最后在MainActivity中,绑定Adapter
1 | public class MainActivity extends AppCompatActivity { |
呈现的效果的话就很简单了,能显示出列表就ok了
ok,现在回归主题,设计一个通用的Adapter来进行数据的显示
先设计一个通用的,实用性高的ViewHolder
其实仔细想,列表中的条目,无非是Textview和ImageView,好像百分之80的条目都是这样,毕竟空间小,也没地方放那么多控件,所以就在ViewHolder里写上TextView和ImageView的复用方法吧。下面有几个关键点
SparseArray
使用 SparseArray 来存放 View 以减少 findViewById 的次数,SparseArray 比 HashMap 更省内存,在某些条件下性能会更好,不过只能存储 key 为 int 类型的数据,正好用来存放资源ID。
getView方法
先从缓存中找,找打的话则直接返回,如果找不到则 findViewById ,再把结果存入缓存中。实现复用
onItemCommonClickListener
其中还定义了一个可扩展的接口,其中定义了两个示例方法。如下
TextView和ImageView的扩展方法
由于上面分析了,条目中一般都用到TextView和ImageView,所以定义几个最常用的方法,以后还可以自己添加
整体代码如下:1
2
3
4
5
6
7
8
9
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
70
71
72
73
74
75
76public class CommonViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
private SparseArray<View> viewSparseArray;
private onItemCommonClickListener commonClickListener;
public CommonViewHolder(@NonNull View itemView) {
super(itemView);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
viewSparseArray = new SparseArray<>();
}
/**
* 先从缓存中找,找打的话则直接返回,如果找不到则 findViewById ,再把结果存入缓存中
*/
public <T extends View> T getView(int viewId) {
View view = viewSparseArray.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
viewSparseArray.put(viewId, view);
}
return (T) view;
}
/**
* 设置textview内容
*/
public CommonViewHolder setText(int viewId, CharSequence text) {
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
/**
* 设置是否可见
*/
public CommonViewHolder setViewVisibility(int viewId, int visibility) {
getView(viewId).setVisibility(visibility);
return this;
}
/**
* 设置图片资源
*/
public CommonViewHolder setImageResource(int viewId, int resourceId) {
ImageView imageView = getView(viewId);
imageView.setImageResource(resourceId);
return this;
}
protected interface onItemCommonClickListener {
void onItemClickListener(int position);
void onItemLongClickListener(int position);
}
public void setCommonClickListener(onItemCommonClickListener commonClickListener) {
this.commonClickListener = commonClickListener;
}
@Override
public void onClick(View view) {
if (commonClickListener != null) {
commonClickListener.onItemLongClickListener(getAdapterPosition());
}
}
@Override
public boolean onLongClick(View view) {
if (commonClickListener != null) {
commonClickListener.onItemClickListener(getAdapterPosition());
}
return true;
}
}
设计通用的RecycleAdapter
再来实现一个通用的 RecyclerView.Adapter
因为不知道要使用到的数据类型是哪一种,也为了更好的适配各种数据类型,所以这里需要用到泛型
当中,onBindViewHolder(CommonViewHolder holder, int position) 需要我们自己来操作,所以这里再来声明一个抽象方法 bindData(CommonViewHolder holder, T data) ,由子类来负责实现绑定操作
1 | abstract class BaseCommonRecycleViewAdapter<T> extends RecyclerView.Adapter<CommonViewHolder> { |
- 大体思路就是把平时老写法的Adapter抽象一层,具体的onCreateViewHolder和onBindViewHolder都在这里进行,才可以减少重复,实现复用。
- 定义了一个bindData的抽象方法,需要在使用过程中进行数据绑定的重写
如何使用编写好的通用Adapter?
重载两个构造方法,一个实现回调自定义接口,另一个不实现,提高扩展性。如下
最后在主页面,就完成了adapter的调用