前言:我们项目中用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