**小飞飞博客之 打造万能适配器**
在Android中ListView不得不说是一个使用频率好高的组件,那么为了提高开发效率我们就有必要将它封装起来;以便以后在编写ListView的适配器的时候随手几行代码将其潇洒的搞定。
那么现在我们要做的任务就是将我们正常书写的Adapter 给封装起来
下面是一个 中规中矩的 MyAdapter 继承 BaseAdapter的代码
public class MyAdapter extends BaseAdapter {
//Context 对象的传入 为的初始化加载布局的LayoutInflater
private Context context;
//lisetview 所绑定的数据集
private List<DataBean> beanList;
private LayoutInflater layoutInflater;
public MyAdapter(Context context, List<DataBean> beanList) {
this.context = context;
this.beanList = beanList;
layoutInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return beanList.size();
}
@Override
public Object getItem(int position) {
return beanList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
/*R.layout.list_myitem 为item条目的布局,还有一些组件的 初始化操作我们都去给用户提供 从外部传入的入口,以及convertView 的复用优化技术我也不再多提,相信大家都知道*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHold viewHold = null;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.list_myitem, parent, false);
viewHold = new ViewHold();
viewHold.dec_tv = (TextView) convertView.findViewById(R.id.dec_tv);
viewHold.time_tv = (TextView) convertView.findViewById(R.id.time_tv);
viewHold.phone_tv = (TextView) convertView.findViewById(R.id.phone_tv);
viewHold.title_tv = (TextView) convertView.findViewById(R.id.title_tv);
convertView.setTag(viewHold);
} else {
viewHold = (ViewHold) convertView.getTag();
}
viewHold.dec_tv.setText(beanList.get(position).getDesc());
viewHold.title_tv.setText(beanList.get(position).getTitle());
viewHold.phone_tv.setText(beanList.get(position).getPhone());
viewHold.time_tv.setText(beanList.get(position).getTime());
return convertView;
}
//这里使用了ViewHold 说白了就是一个持有类 为的是 初始化组件(findviewbyid操作)不去执行那么多遍
static class ViewHold {
TextView title_tv;
TextView dec_tv;
TextView phone_tv;
TextView time_tv;
}
}
对于上面代码 大家估计是码的都快吐了,那么接下来我们将它抽取成为一万能的适配器 我们分析发现BaseAdapter 里面大多数代码都是重复的 包括复写的几个方法都是固定的几个,唯一特殊的方法就是getView方法了。但是getView 方法的流程也是定死了的,大概分为一下几部
1: 为了复用convertView 布局, 先判空 为空去加载布局
2:new 出viewhold 去初始化viewhold里持有的组件,然后将viewhold 通过View类里的 setTag() 方法将viewhold对象寄存在 convertView对象中
3:如果convertView 不为空的话直接 用 getTag() 方法将持有组件的viewhold 对象取出
4:接下来设置 组件上对应数据的值
5:最后返回 convertView 就可以了
我们可以发现上面的几步,也仅仅是第 4 步,每个人的操作不一样,因为每个人的数据不同;
接下来 我们写一个ViewHold类 将以上共同的 1 2 3 5 步给封装起来
public class ViewHold {
private int postion;
private View mConvertView;
private Context mContext;
//这个集合 用于给用户初始化 控件。也就是说 对应的View控件 和Id 键值成对
//存放在集合里 这样就不必 每一次都去 findViewById 了
private SparseArray mSparseArray = new SparseArray<>();
public View getmConvertView() {
return mConvertView;
}
public ViewHold(int postion, View mConvertView, Context mContext, int ResLayoutId, ViewGroup parent) {
mConvertView = LayoutInflater.from(mContext).inflate(ResLayoutId, parent, false);
this.postion = postion;
this.mConvertView = mConvertView;
this.mContext = mContext;
mConvertView.setTag(this);
}
//相当于将 判空操作 和 setTag 与 getTag 操作执行了
public static ViewHold getViewHold(Context mContext, int postion, View mConvertView, int ResLayoutId, ViewGroup parent) {
if (mConvertView == null) {
//跳转到 构造函数 为空加载布局 携带 viewHold 操作
return new ViewHold(postion, mConvertView, mContext, ResLayoutId, parent);
} else {
//不为空 取出 ViewHold 对象
ViewHold viewhold = (ViewHold) mConvertView.getTag();
return viewhold;
}
}
//这个方法 为了解决用户书写 适配器 初始化控件的控件的操作;
//具体逻辑 如果集合中没有还有存放初始化好的组件 就FindViewById 加入集合,下次用有就直接取就OK了
//使用 泛型 T 的目的是 我并不知道 你有哪些控件 我只能知道的是的组件必然是View的子类,你拿到View自行强转
public T getView(int ResId) {
View view = mSparseArray.get(ResId);
if (view == null) {
view = mConvertView.findViewById(ResId);
mSparseArray.put(ResId, view);
}
return (T) view;
}
}
这样一来在写BaseAdapter的getView()方法时
我们只需要 :
public View getView(int position, View convertView, ViewGroup parent) {
ViewHold viewHold = ViewHold.getViewHold(mContext, position, convertView, R.layout.mylist_item, parent);
((TextView) viewHold.getView(R.id.id_title)).setText(list_data.get(position).getmTitle());
((TextView) viewHold.getView(R.id.id_content)).setText(list_data.get(position).getmContent());
((TextView) viewHold.getView(R.id.id_time)).setText(list_data.get(position).getmTime());
return viewHold.getmConvertView();
}
相比以前是不是简单多了
先 getVIewHold() 再找组件 再返回 convertView
中间的初始化组件的是必须要写的,但 开始的getVIewHold() 和 最后的 返回convertView 操作我们还可以继续抹掉
写一个名为CompanyAdapter的抽象类 继承 BaseAdapter
public abstract class CompanyAdapter extends BaseAdapter {
protected Context mContext;
protected List list_data;
protected int LayoutItmeResId;
public CompanyAdapter(Context mContext, List<T> list_data, int LayoutItemResId) {
this.list_data = list_data;
this.mContext = mContext;
this.LayoutItmeResId = LayoutItemResId;
}
@Override
public int getCount() {
return list_data.size();
}
@Override
public Object getItem(int position) {
return list_data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHold viewHold = ViewHold.getViewHold(mContext, position, convertView, LayoutItmeResId, parent);
initView(viewHold, position);
return viewHold.getmConvertView();
}
protected abstract void initView(ViewHold viewhold, int position);
}
可以看到我们将要做的相同的操作全部放在了这个抽象类中
只提供了一个抽象方法 initView方法 那便你为组件设置值的接口
那么我们的万能 适配器基本上算大功告成了
让我们来使用一下看看![里面MyAdapter包里是我们刚刚写好的两个工具类](https://img-blog.csdn.net/20160521115909318)
里面MyAdapterUtils包里是我们刚刚写好的两个工具类
public class MainActivity extends AppCompatActivity {
private List dataRusList;
private ListView mListView;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataRusList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
DataRus mDataRus = new DataRus("万能适配器" + i, "我的第" + i + "个条目", "2016.5." + (20+i));
dataRusList.add(mDataRus);
}
mListView = (ListView) findViewById(R.id.listview);
//使用的时候传3个参数 最后一个为item的布局
myAdapter = new MyAdapter(this, dataRusList,R.layout.mylist_item);
mListView.setAdapter(myAdapter);
}
}
Item的布局就不贴了 重点是适配器
public class MyAdapter extends CompanyAdapter<DataRus> {
public MyAdapter(Context mContext, List<DataRus> list_data, int LayoutItemResId) {
super(mContext, list_data, LayoutItemResId);
}
//这里初始化你的控件
protected void initView(ViewHold viewHold,int position) {
((TextView)viewHold.getView(R.id.id_title)).setText(list_data.get(position).getmTitle());
((TextView) viewHold.getView(R.id.id_content)).setText(list_data.get(position).getmContent());
((TextView) viewHold.getView(R.id.id_time)).setText(list_data.get(position).getmTime());
}
}
最后附上我最后 丑丑的运行结果图,没怎么认真的找素材,全是TextView