本文介绍通过抽象ViewHolder和BaseAdapter来简化我们重写BaseAdapter时的步骤
前提描述:
我们在使用ListView时自然要用ViewHolder来优化ListView,步骤往往是,1.继承BaseAdapter,2.创建一个ViewHolder类,3.在getView中做处理
当我们app有很多很多个ListView或者GridView时,写很多很多BaseAdapter就是个麻烦事了...
既然ViewHolder都是类似的,我们何不把他抽象出来。还有BaseAdapter也可以在抽象一层出来,会省很多事哦。
抽象共同的ViewHolder
ViewHolder的工作是完成ViewHolder下面定义的各种子控件,并在必要的时候把这个ViewHolder setTag给getView 的 convertView中,复用的时候再拿出来继续用。除此之外就没有其他的工作了。回想一下常规的写法,我们需要在getView中用LayoutInflate.from(this).inflate()去初始化ViewHolder。所以ViewHolder初始化的方法不能少,初始化的时候需要根据layoutId,所有得有一个接口留给子类调用。
抽象ViewHolder
——view viewInflate(context,viewgroup,attach)
——getItemLayout() 留给子类实现的接口,届时传递一个布局的id经来,用来初始化ViewHolder
初始化的控件需要放在一个容器中暂时存起来
容器ViewHolder
——容器
——View 当前视图
——根据当前视图找自己的子控件
CommonViewHolder.java (抽象的ViewHolder)
public abstract class CommonViewHolder {
private Context mContext;
/**
* 当前项的view
*/
private View mItemView;
/**
* 用来零时存储ViewHolder的子View和初始化它们
*/
private CommonViewHolderHelper mHolderHelper;
/**
* 用来加载ViewHolder的视图View,根据layoutId
*/
public View viewInflate(Context context, ViewGroup parent, boolean attachToRoot) {
mContext = context;
mItemView = LayoutInflater.from(mContext).inflate(getItemLayout(), parent, attachToRoot);
mItemView.setTag(this);
mHolderHelper = new CommonViewHolderHelper(mItemView);
initItemView();
return mItemView;
}
/**
* 根据layoutI找到ItemView,这个工作只在这里声明,然后在viewInflaite里面调用,具体的实现工作交给子类去完成
*
* @return 发挥当前ViewHolder所需的布局或者是视图
*/
public abstract int getItemLayout();
/**
* 初始化item的子View
*/
public void initItemView() {
}
/**
* 初始化View根据layoutId
*
* @param layoutId 需要初始化的View的id
* @return
*/
public <T extends View> T findViewById(int layoutId) {
return mHolderHelper.findViewById(layoutId);
}
}
CommonViewHolderHelper.java (抽象的ViewHolder帮助类,用来存子View)
public class CommonViewHolderHelper {
/**
* 用来装ViewHolder的View的容器
*/
private SparseArray<View> mViewArray = new SparseArray<View>();
/**
* ViewHolder的布局
*/
private View mConvertView;
public CommonViewHolderHelper(View view) {
mConvertView = view;
}
public CommonViewHolderHelper(Context context, int layoutId) {
this(context, null, layoutId);
}
public CommonViewHolderHelper(Context context, ViewGroup group, int layoutId) {
this(LayoutInflater.from(context).inflate(layoutId, group, false));
}
public View getView() {
return mConvertView;
}
/**
* 从SparseArray找出子View根据id
*
* @param layoutId 返回itemview中子控件时所需的layoutid
* @return
*/
public <T extends View> T findViewById(int layoutId) {
View view = mViewArray.get(layoutId);
if (view == null) {
view = mConvertView.findViewById(layoutId);
if (view != null) {
mViewArray.put(layoutId, view);
}
}
return view == null ? null : (T) view;
}
}
然后接下来就是重写BaseAdapter了,前面我们定义的CommonViewHolder就是给这一步准备的。我们以泛型的方式把CommonViewHolder和数据模型传给CommonBaseAdapter,然后在CommonBaseAdapter里面做好处理,并且留给外界访问的接口,到时候直接调用就跟方便了。
留给子类以传入ViewHolder的接口,getView使用该返回值来进行ViewHolder的初始化。
留给子类对ItemView的数据进行操作的接口
CommonAdapter.java (抽象一个BaseAdapter,传入数据模型和ViewHolder)
public abstract class CommonAdapter<T, H extends CommonViewHolder> extends BaseAdapter {
private Context mContext;
/**
* 用来存储adapter数据的List
*/
private List<T> mDatas = new ArrayList<T>();
public CommonAdapter(Context context) {
this.mContext = context;
}
public void setDatas(List<T> list) {
mDatas = list;
notifyDataSetChanged();
}
@Override
public int getCount() {
return mDatas.size();
}
@Override
public Object getItem(int arg0) {
return mDatas.get(arg0);
}
@Override
public long getItemId(int arg0) {
return arg0;
}
@Override
public View getView(int position, View convertView, ViewGroup group) {
if (convertView == null) {
convertView = initViewHolder().viewInflate(mContext, group, false);
}
H h = (H) convertView.getTag();
initItemData(position, h, convertView);
return convertView;
}
/**
* 返回ViewHolder子视图的抽象方法,在getView中调用,然后在子类中具体实现
*
* @return 返回ViewHolder
*/
protected abstract H initViewHolder();
/**
* 设置Item中的数据,抽象的方法,在getView中调调用,然后在子类中初始化
*
* @param position
* itemview的索引
* @param viewholder
* 实现的ViewHolder子类
* @param root
* itemview 的子视图
*/
protected abstract void initItemData(int position, H viewholder, View root);
}
这样就大功告成了,我们来看看如何使用:
1.创建一个ViewHolder,它继承自CommonViewHolder
2.用刚刚创建好的ViewHolder来创建CommonBaseAdapter
3.给数据,调用
MyViewHolder.java (测试用的ViewHolder)
public class MyViewHolder extends CommonViewHolder {
public TextView mTitle;
public TextView mContent;
@Override
public int getItemLayout() {
return R.layout.test_listview_item;
}
@Override
public void initItemView() {
super.initItemView();
mTitle = findViewById(R.id.test_listview_item1);
mContent = findViewById(R.id.test_listview_item2);
}
}
所需的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/test_listview_item1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="76dp"
android:layout_marginTop="33dp" />
<TextView
android:id="@+id/test_listview_item2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="40dp"
android:layout_marginTop="16dp" />
</RelativeLayout>
MyAdapter.java (使用上面的MyViewHolder来创建一个Adapter)public class MyAdapter extends CommonAdapter<TestBean, MyViewHolder> {
public MyAdapter(Context context) {
super(context);
}
@Override
protected MyViewHolder initViewHolder() {
return new MyViewHolder();
}
@Override
protected void initItemData(int position, MyViewHolder viewholder, View root) {
TestBean bean = (TestBean) getItem(position);
viewholder.mTitle.setText(bean.getmTitle().toString());
viewholder.mContent.setText(bean.getmContent().toString());
}
}
在Activity中使用时:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.test_listview);
mBeans = new ArrayList<TestBean>();
for (int i = 0; i < 100; i++) {
TestBean bean = new TestBean("title=" + i, "content" + i);
mBeans.add(bean);
}
// mListView.setAdapter(new TestAdapter(this, mBeans));
MyAdapter adapter = new MyAdapter(this);
// MyAdapter2 adapter = new MyAdapter2(this);
// adapter.setDatas(mBeans);
mListView.setAdapter(adapter);
}
效果:
然后,当我们有一个新的ListView的时候,或者要给这个ListView跟换内容时,只需要三步
1.新建一个布局文件
2.新建一个CommonViewHolder的子类,在里面初始化子控件
3.新建一个CommentBaseAdapter的子类,在里面给子控件赋值,把这个adapter设置给ListView
下载链接:http://download.csdn.net/detail/u013045971/9215387