前言:我們項目中用ListView和RecyclerView的情況會非常多,每次寫Adapter會不會覺得很繁瑣,明明很多代碼都差不多,本文将帶領大家一步一步打造一個萬能BaseListAdapter。
一:一般寫法
- MainActivity
public class MainActivity extends AppCompatActivity {
private ListView lv_main;
private List<Bean> mList;
private PersonAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv_main = findViewById(R.id.lv_main);
initData();
initView();
}
private void initData() {
mList = new ArrayList<>();
mList.add(new Bean("xiaoming 1", "湖南省長沙市天心區", 18));
mList.add(new Bean("xiaoming 2", "湖南省長沙市天心區", 18));
mList.add(new Bean("xiaoming 3", "湖南省長沙市天心區", 18));
mList.add(new Bean("xiaoming 4", "湖南省長沙市天心區", 18));
mList.add(new Bean("xiaoming 5", "湖南省長沙市天心區", 18));
mList.add(new Bean("xiaoming 6", "湖南省長沙市天心區", 18));
}
private void initView() {
mAdapter = new PersonAdapter(mList, this);
lv_main.setAdapter(mAdapter);
}
}
- PersonAdapter
public class PersonAdapter extends BaseAdapter {
private List<Bean> mList;
private Context mContext;
private LayoutInflater mInflater;
public PersonAdapter(List<Bean> mList, Context context) {
this.mList = mList;
this.mContext = context;
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return (mList == null) ? 0 : mList.size();
}
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_list, parent, false);
viewHolder = new ViewHolder();
viewHolder.tv_name = convertView.findViewById(R.id.tv_name);
viewHolder.tv_address = convertView.findViewById(R.id.tv_address);
viewHolder.tv_age = convertView.findViewById(R.id.tv_age);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag(position);
}
Bean bean = mList.get(position);
viewHolder.tv_name.setText(bean.getName());
viewHolder.tv_address.setText(bean.getAddress());
viewHolder.tv_age.setText("年齡:"+bean.getAge());
return convertView;
}
private class ViewHolder {
private TextView tv_name;
private TextView tv_address;
private TextView tv_age;
}
}
- 實體類Bean(基礎和萬能Adapter都一樣)
public class Bean {
private String name;
private String address;
private int age;
...//省略set,get和construct方法
}
- xml布局(省略)
- 運作效果
打造适配ListView的萬能BaseAdapter
二、把ViewHolder抽取出來,打造萬能ViewHolder
- 建立CommonViewHolder
public class CommonViewHolder {
private SparseArray<View> mViews;
private View mConvertView;
private int mPosition;
public CommonViewHolder(Context mContext, ViewGroup parent, int position, int resId) {
this.mPosition = position;
mViews = new SparseArray<>();
mConvertView = LayoutInflater.from(mContext).inflate(resId, parent, false);
mConvertView.setTag(this);
}
public static CommonViewHolder get(Context mContext, View convertView, ViewGroup parent, int position, int resId) {
if (convertView == null) {
return new CommonViewHolder(mContext, parent, position, resId);
} else {
CommonViewHolder viewHolder = (CommonViewHolder) convertView.getTag();
viewHolder.mPosition = position;
return viewHolder;
}
}
/**
* 通過VIewid擷取控件
*
* @param viewId
* @param <T>
* @return
*/
public <T extends View> T getView(int viewId) {
T view = (T) mViews.get(viewId);
if (view == null) {
view = (T) mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}
return view;
}
public View getConvertView() {
return mConvertView;
}
}
- 修改PersonAdapter中getView()代碼
...//省略
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//這邊一句代碼就做了上邊擷取ViewHolder的工作
CommonViewHolder viewHolder = CommonViewHolder.get(mContext, convertView, parent, position, R.layout.item_list);
Bean bean = mList.get(position);
//使用CommonViewHolder中的getView方法設定資料
((TextView) viewHolder.getView(R.id.tv_name)).setText(bean.getName());
((TextView) viewHolder.getView(R.id.tv_address)).setText(bean.getAddress());
((TextView) viewHolder.getView(R.id.tv_age)).setText("年齡:" + bean.getAge());
return viewHolder.getConvertView();
}
...//省略
- 次改後運作上述代碼,發現運作成功。我們的代碼簡潔許多,萬能ViewHolder初步打造完成。
三、完善CommonViewHolder,可以看到上部分有很多setText方法,我們将setText抽取出來,相應的還可以抽取setImageResource等等。
- 修改CommonViewHolder
...//省略
public CommonViewHolder setText(int viewId,String text){
((TextView)getView(viewId)).setText(text);
return this;
}
public CommonViewHolder setImageResource(int viewId,int resId){
((ImageView)getView(viewId)).setImageResource(resId);
return this;
}
...//省略
- 相應修改PerAdapter代碼
Bean bean = mList.get(position);
viewHolder.setText(R.id.tv_name,bean.getName())
.setText(R.id.tv_address,bean.getAddress())
.setText(R.id.tv_age,"年齡:" + bean.getAge());
- 修改後運作成功,我們的CommonViewHolder打造完成,當然,除了setText、setImageResource,你還可以根據項目需要寫一些需要的方法。
四、打造萬能Adapter。(在寫代碼的過程中,我們會發現大部分的adapter,getCount、getItem、getItemId寫的代碼都差不多,初步我們就将它們提取出來)
- 打造CommonListAdapter,提取getCount、getItem、getItemId
public abstract class CommonListAdapter<T> extends BaseAdapter {
//泛型List
private List<T> mDatas;
public CommonListAdapter(List<T> mDatas) {
this.mDatas = mDatas;
}
@Override
public int getCount() {
return (mDatas == null)?0:mDatas.size();
}
@Override
public Object getItem(int position) {
return mDatas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public abstract View getView(int position, View convertView, ViewGroup parent);
}
- 修改PersonAdapter代碼
public class PersonAdapter extends CommonListAdapter {
private Context mContext;
private List<Bean> mList;
public PersonAdapter(List mDatas,Context context) {
super(mDatas);
this.mContext = context;
this.mList = mDatas;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
CommonViewHolder viewHolder = CommonViewHolder.get(mContext, convertView, parent, position, R.layout.item_list);
Bean bean = mList.get(position);
((TextView) viewHolder.getView(R.id.tv_name)).setText(bean.getName());
((TextView) viewHolder.getView(R.id.tv_address)).setText(bean.getAddress());
((TextView) viewHolder.getView(R.id.tv_age)).setText("年齡:" + bean.getAge());
return viewHolder.getConvertView();
}
}
- 運作代碼,嗯,跟我們之前的效果一模一樣,Adapter的代碼量也相應減少。萬能Adapter初步完成。
五、我們可以看到,CommonListAdapter中我們傳遞了資料mData,但是PersonAdapter的getView中依然要擷取,而且viewHolder 和最後return也是差不多的寫法,我們每次布局不可能一樣,我們是否可以再次優化CommonListAdapter中的getView呢?
- 再次優化CommonListAdapter
public abstract class CommonListAdapter<T> extends BaseAdapter {
//泛型List
private List<T> mDatas;
private Context mContext;
private int mLayoutId;
public void setmDatas(List<T> mDatas) {
this.mDatas = mDatas;
}
public CommonListAdapter(Context context,,int layoutId) {
this.mContext = context;
this.mLayoutId = layoutId;
}
...//省略
@Override
public View getView(int position, View convertView, ViewGroup parent){
CommonViewHolder viewHolder = CommonViewHolder.get(mContext, convertView, parent, position,mLayoutId);
T bean = mDatas.get(position);
convert(viewHolder,bean);
return viewHolder.getConvertView();
}
public abstract void convert(CommonViewHolder viewHolder,T bean);
}
- 再來寫我們的PersonAdapter
public class PersonAdapter extends CommonListAdapter<Bean> {
public PersonAdapter(List mDatas,Context context) {
super(context,layoutId);
setmDatas(mDatas);
}
@Override
public void convert(CommonViewHolder viewHolder,Bean bean) {
((TextView) viewHolder.getView(R.id.tv_name)).setText(bean.getName());
((TextView) viewHolder.getView(R.id.tv_address)).setText(bean.getAddress());
((TextView) viewHolder.getView(R.id.tv_age)).setText("年齡:" + bean.getAge());
}
}
- 運作,效果杠杠滴(可以看到經過上述幾部已經将PersonAdapter的代碼簡化簡化再簡化了,我們的CommonViewHolder和CommonListAdapter相信也可以滿足大部分的項目需要了)。
六、有些ListView展示的資料很簡單,我們就沒有必要另外寫一個類去繼承CommonListAdapter了,直接使用匿名内部類會簡單些。
- 修改MainActivity代碼
private void initView() {
// mAdapter = new PersonAdapter(mList, this);
//這裡使用匿名内部類就不需要再去建立類
lv_main.setAdapter(new CommonListAdapter<Bean>(mList,MainActivity.this,R.layout.item_list) {
@Override
public void convert(CommonViewHolder viewHolder, Bean bean) {
viewHolder.setText(R.id.tv_name,bean.getName())
.setText(R.id.tv_address,bean.getAddress())
.setText(R.id.tv_age,"年齡:" + bean.getAge());
}
});
}
七、總優化(延伸思考和總結)
- 思考:在實際使用過程中,因為還涉及到重新整理,我們需要把資料提取出來單獨寫一個方法設定,還有我們ListVIew的多布局情況,如果用到這些都是需要考慮的。
-
總結:平時項目中用到了萬能Adapter,也修改過其中的代碼,這次看了慕課網的課程:https://www.imooc.com/learn/372
完完整整的理了一遍,還是需要不斷學習。請加油。
- 最後貼上demo下載下傳位址,可直接下載下傳運作 https://github.com/xiaomei888/baselistadapter/tree/master