Android简便通用SimpleBaseAdapter

SimpleBaseAdapter主要是解决了每次都要重写BaseAdapter那几个方法,还有优化了ViewHolder。我们可以先看看常见的Adapter写法。

0x00 常见Adapter

常见的Adapter大家都很熟了,直接贴代码:

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
public class NormalAdapter extends BaseAdapter {
private Context context;
private List<String> data;
public NormalAdapter(Context context, List<String> data){
this.context = context;
this.data = data;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
holder = new ViewHolder();
convertView = View.inflate(context, R.layout.menu_item, null);
holder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.tvContent.setText(data.get(position));
return convertView;
}
class ViewHolder{
TextView tvContent;
}
}

0x01 抽象方法

我们可以直接抽象一个SimpleBaseAdapter。解决上面代码中每次都需要重写复写的方法。
代码如下:

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
public abstract class SimpleBaseAdapter<T> extends BaseAdapter {
private Context mContext;
private List<T> mData;
public SimpleBaseAdapter(Context context, List<T> data) {
this.mContext = context;
this.mData = data == null ? new ArrayList<T>() : data;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
if (position >= mData.size())
return null;
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
}

0x02 优化ViewHolder

上面代码只解决了代码复写的问题并没有getView()和ViewHolder,ViewHolder其实只要是作为ListView缓存的子选项,常见的写法是把子选项硬编码写在ViewHolder所以没有办法通用,我们可以考虑用列表保存选择子选项的控件。
优化后的ViewHolder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ViewHolder {
private SparseArray<View> views = new SparseArray<>();
private View convertView;
public ViewHolder(View view) {
this.convertView = view;
}
public <T extends View> T getView(int resId) {
View view = views.get(resId);
if (view == null) {
view = convertView.findViewById(resId);
views.put(resId, view);
}
return (T) view;
}
}

SparseArray在代码理解上等价于HashMap, SparseArray是Android提供的一个数据结构,但是比Map的效率更高。

PS: 如果你用到了ExpandableListView 需要重写BaseExpandableListAdapter那么上述的代码就不直接用了,但是ViewHolder还是可以通用的。所以如果项目中不止重写了BaseAdapter可以将ViewHolder提出来提高复用。

0x03 源码

完整SimpleBaseAdapter:

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
76
77
78
79
80
public abstract class SimpleBaseAdapter<T> extends BaseAdapter {
private Context mContext;
private List<T> mData;
public SimpleBaseAdapter(Context context, List<T> data) {
this.mContext = context;
this.mData = data == null ? new ArrayList<T>() : data;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
if (position >= mData.size())
return null;
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(null == convertView){
convertView = View.inflate(mContext, getItemResource(), null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
return getItemView(position, convertView, viewHolder);
}
/**
* 该方法需要子类实现,需要返回item布局的resource id
*
* @return resource id
*/
public abstract int getItemResource();
/**
* 使用该getItemView方法替换原来的getView方法,需要子类实现
*
* @param position
* @param convertView
* @param viewHolder
* @return
*/
public abstract View getItemView(int position, View convertView, ViewHolder viewHolder);
//数据操作
public void addAll(List<T> elem) {
mData.addAll(elem);
notifyDataSetChanged();
}
public void remove(T elem) {
mData.remove(elem);
notifyDataSetChanged();
}
public void remove(int index) {
mData.remove(index);
notifyDataSetChanged();
}
public void replaceAll(List<T> elem) {
mData.clear();
mData.addAll(elem);
notifyDataSetChanged();
}
}

使用示例

继承SimpleBaseAdapter,并且实现getItemResource和getItemView两个方法。
示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class TestAdapter extends SimpleBaseAdapter<String> {
public TestAdapter(Context context, List<String> data) {
super(context, data);
}
@Override
public int getItemResource() {
return R.layout.menu_item;
}
@Override
public View getItemView(int position, View convertView, ViewHolder viewHolder) {
TextView tvContent = viewHolder.getView(R.id.tv_content);
tvContent.setText((String)getItem(position));
return convertView;
}
}