在Android项目中,经常都会用到ListView这个控件,而相应的Adapter中getView()方法的编写有一个标准的形式,如下:
复制代码
1 @Override
2public View getView(int position, View convertView, ViewGroup parent) {
3ViewHolder holder;
4if(null == convertView){
5holder = new ViewHolder();
6LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
7convertView = mInflater.inflate(R.layout.item, null);
8holder.btn = (Button) convertView.findViewById(R.id.btn);
9holder.tv = (TextView) convertView.findViewById(R.id.tv);
10holder.iv = (TextView) convertView.findViewById(R.id.iv);
11
12convertView.setTag(holder);
13}else{
14holder = (ViewHolder) convertView.getTag();
15}
16final HashMap<String, Object> map = list.get(position);
17
18holder.iv.setImageResource(Integer.valueOf(map.get("iv").toString()));
19holder.tv.setText(map.get("tv").toString());
20
21holder.btn.setOnClickListener(new View.OnClickListener() {
22@Override
23public void onClick(View v) {
24Toast.makeText(context, map.get("btn").toString(), Toast.LENGTH_SHORT).show();
25}
26});
27
28return convertView;
29}
30
31 class ViewHolder{
32Button btn;
33ImageView iv;
34TextView tv;
35
36}
复制代码
以下是碎碎念(想直接看代码的,就跳过这段吧-_-!):
也就是说每次编写Adapter都需要编写class ViewHolder...、if(null == convertView){...等等。这些代码跟业务逻辑关系不大,没有必要每次都写重复代码,
所以,显然有简化代码的余地。
既然我们的需求是不需要重复编写ViewHolder等内部类,那就把它移到父类吧。
但是ViewHolder中在实际项目中有不同的View,那就用list存放起来吧,但是放在list中的话,怎么取出来?用index?显然不是好的方法,不是有Resource Id这玩意,通过这个取不就好了么?所以以Resource Id为key放在Map中比较合适,但是既然以int(Resource Id)为key,那自然而然想到使用SparseArray了。
然后再把if(null == converView)...这些代码统统移到父类中。
所以ABaseAdapter诞生了,代码如下:
复制代码
1 /**
2* 实现对BaseAdapter中ViewHolder相关的简化
3* Created with IntelliJ IDEA.
4* Author: wangjieemail:tiantian.china.2@gmail.com
5* Date: 14-4-2
6* Time: 下午5:54
7*/
8 public abstract class ABaseAdapter extends BaseAdapter{
9Context context;
10
11protected ABaseAdapter(Context context) {
12this.context = context;
13}
14
15protected ABaseAdapter() {
16}
17
18/**
19* 各个控件的缓存
20*/
21class ViewHolder{
22public SparseArray<View> views = new SparseArray<View>();
23
24/**
25* 指定resId和类型即可获取到相应的view
26* @param convertView
27* @param resId
28* @param <T>
29* @return
30*/
31<T extends View> T obtainView(View convertView, int resId){
32View v = views.get(resId);
33if(null == v){
34v = convertView.findViewById(resId);
35views.put(resId, v);
36}
37return (T)v;
38}
39
40}
41
42/**
43* 改方法需要子类实现,需要返回item布局的resource id
44* @return
45*/
46public abstract int itemLayoutRes();
47
48@Override
49public View getView(int position, View convertView, ViewGroup parent) {
50ViewHolder holder;
51if(null == convertView){
52holder = new ViewHolder();
53convertView = LayoutInflater.from(context).inflate(itemLayoutRes(), null);
54convertView.setTag(holder);
55}else{
56holder = (ViewHolder) convertView.getTag();
57}
58return getView(position, convertView, parent, holder);
59}
60
61/**
62* 使用该getView方法替换原来的getView方法,需要子类实现
63* @param position
64* @param convertView
65* @param parent
66* @param holder
67* @return
68*/
69public abstract View getView(int position, View convertView, ViewGroup parent, ViewHolder holder);
70
71 }
复制代码
如上代码:增加了一个itemLayoutRes()的抽象方法,该抽象方法提供给子类实现,返回item布局的resource id,为后面的getView方法提供调用。
可以看到上述代码中,在系统的getView方法中,进行我们以前在BaseAdapter实现类中所做的事(初始化converView,并绑定ViewHolder作为tag),然后抛弃了系统提供的getView方法,直接去调用自己写的getView抽象方法,这个getView方法是提供给子类去实现的,作用跟系统的getView一样,但是这个getView方法中携带了一个ViewHolder对象,子类可以通过这个对象进行获取item中的控件。
具体使用方式如下,比如创建了MyAdapter并继承了ABaseAdapter:
注意,在构造方法中需要调用父类的构造方法:
1 public MyAdapter(Context context, List<HashMap<String, Object>> list) {
2super(context);
3this.list = list;
4 }
即,以上的“super(context);”必须调用。
接着实现itemLayoutRes()方法,返回item的布局:
1 @Override
2 public int itemLayoutRes() {
3return R.layout.item;
4 }
getView方法中的实现如下:
复制代码
1 @Override
2 public View getView(int position, View convertView, ViewGroup parent, ViewHolder holder) {
3final HashMap<String, Object> map = list.get(position);
4
5Button btn = holder.obtainView(convertView, R.id.item_btn);
6ImageView iv = holder.obtainView(convertView, R.id.item_iv);
7TextView tv = holder.obtainView(convertView, R.id.item_tv);
8
9btn.setOnClickListener(new View.OnClickListener() {
10@Override
11public void onClick(View v) {
12Toast.makeText(context, map.get("btn").toString(), Toast.LENGTH_SHORT).show();
13}
14});
15
16iv.setImageResource(Integer.valueOf(map.get("iv").toString()));
17tv.setText(map.get("tv").toString());
18
19return convertView;
20}
复制代码
如上代码:调用holder.obtainView方法既可获取item中的控件;