尝试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; } }