尝试Android中ViewHolder模式进行封装的实践
提供一个ViewHolder接口,约定其实现类具有一个以View为参数的构造器,构造器中写各种findViewById。接口方法bindItem提供将item显示到View的方法。
对Adapter以及ArrayAdapter作出扩展,简化关于View回收判断部分的代码。
以下为具体实现。
package com.zwb.commonlibs.adapters;
/**
* 为{@link ArrayViewHolderAdapter}及{@link ViewHolderAdapter}提供ViewHolder,
* 提供从convertView生成ViewHolder的构造器和从item生成视图的方法
*
* @author zwb
*/
public interface ViewHolder {
/**
* 由item生成视图
*
* @param o 传入的item
* @param position adapter中的位置
*/
void bindItem(Object o, int position);
}
package com.zwb.commonlibs.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.lang.reflect.Constructor;
/**
* 使用{@link ViewHolder}的{@link BaseAdapter}
*/
public abstract class ViewHolderAdapter extends BaseAdapter {
@Override
public long getItemId(int position) {
return position;
}
protected abstract int getResId(int viewType);
protected abstract Class<? extends ViewHolder> getViewHolderClass(int viewType);
@Override
public final View getView(int position, View convertView, ViewGroup parent) {
int viewType = getItemViewType(position);
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(getResId(viewType), parent, false);
try {
Constructor<? extends ViewHolder> constructor = getViewHolderClass(viewType).getConstructor(View.class);
ViewHolder viewHolder = constructor.newInstance(convertView);
convertView.setTag(viewHolder);
} catch (Exception e) {
throw new RuntimeException("ViewHolder必须有一个View参数的构造器");
}
}
//noinspection unchecked
ViewHolder viewHolder = (ViewHolder) convertView.getTag();
viewHolder.bindItem(getItem(position), position);
return convertView;
}
}
package com.zwb.commonlibs.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import java.lang.reflect.Constructor;
import java.util.List;
/**
* 使用{@link ViewHolder}的{@link ArrayAdapter}
*
* @param <T> 数据类型
* @author zwb
*/
public class ArrayViewHolderAdapter<T> extends ArrayAdapter<T> {
protected LayoutInflater mLayoutInflater;
private int mResource;
private Constructor<? extends ViewHolder> mConstructor;
public ArrayViewHolderAdapter(Context context, int resource, Class<? extends ViewHolder> class1) {
super(context, 0);
init(context, resource, class1);
}
public ArrayViewHolderAdapter(Context context, int resource, List<T> objects, Class<? extends ViewHolder> class1) {
super(context, 0, objects);
init(context, resource, class1);
}
private void init(Context context, int resource, Class<? extends ViewHolder> clazz) {
mResource = resource;
mLayoutInflater = LayoutInflater.from(context);
try {
mConstructor = clazz.getConstructor(View.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(clazz.getName() + " 必须带有View参数的构造器");
}
}
@Override
public final View getView(int position, View convert, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convert == null) {
convert = mLayoutInflater.inflate(mResource, parent, false);
try {
viewHolder = mConstructor.newInstance(convert);
} catch (Exception e) {
e.printStackTrace();
}
convert.setTag(viewHolder);
} else {
//noinspection unchecked
viewHolder = (ViewHolder) convert.getTag();
}
//noinspection ConstantConditions
viewHolder.bindItem(getItem(position), position);
return convert;
}
}
以下为两个Demo
使用ArrayViewHolderAdapter
public class ViewHolderImpl implements ViewHolder {
private final TextView name, time, code;
public ViewHolderImpl(View view) {
name = (TextView) view.findViewById(R.id.textName);
time = (TextView) view.findViewById(R.id.textTime);
code = (TextView) view.findViewById(R.id.textCode);
}
@Override
public void bindItem(Object o, int position) {
DataObject item = (DataObject) o;
name.setText(item.getName());
time.setText(item.getTime());
code.setText(item.getCode());
}
}
//创建Adapter
ArrayAdapter<DataObject> adapter=new ArrayViewHolderAdapter<>(context,R.layout.data_object,ViewHolderImpl.class);
使用ViewHolderAdapter
public class ViewHolder1 implements ViewHolder{
//实现同上
}
public class ViewHolder2 implements ViewHolder{
//实现同上
}
public class MyAdapter extends ViewHolderAdapter{
public Object getItem(int position){
//TODO
}
public int getItemCount(){
//TODO
}
public int getViewTypeCount(){
return 2;
}
public int getItemViewType(int position){
//TODO
}
public Class<? extends ViewHolder> getViewHolderClass(int viewType){
return viewType==0?ViewHolder1.class:ViewHolder2.class;
}
public int getResId(int viewType){
return viewType==0?R.layout.item1:R.layout.item2;
}
}