本文介紹通過抽象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