为何要使用万能适配器?
在安卓开发中,用到ListView和GridView的地方很多,如果你是开发一个简单点的APP还好,可能ListView和GridView的数量不会太多,我们只要去写几个BaseAdapter实现类就可以了。但如果有一天,你需要开发一个APP里面具有几十个ListView的子页面,此时的你该怎么办?每个ListView或GridView都去写一个适配的Adatper类吗?
这个时候就要想办法让自己减少很多工作量,避免做重复无意义劳动。
概念
就像上面说的我们每次都需要去继承一个BaseAdapter,然后实现里面的一大堆方法,而我们每次最关心的无非就是getView方法,其余的方法几乎都是相同代码。这里是不是就可以优化起来呢?在其次,我们在使用Adapter的时候,为了优化性能,常常会创建一个Holder。而Holder里面每次存放的都是View,对Holer的操作无非也就是初始化,绑定数据,复用。这里我们就抽取出两个类分别是CommonViewHolder和CommonAdapter来存放相同的东西。 好了,废话不多说,直接上代码。
第一步抽取出通用ViewHolder:
/**
* 通用的ViewHolder
* 照顾下初次使用SparseArray 其实它是Android推荐使用的一个优化容器,相当于一个Map<integer,View>
* 目的是为了提供效率,其核心算法是折半查找,其用法和Map无两异。
* Created by lx_yoyo on 2016/8/10.
*/
public class CommonViewHolder {
private SparseArray<View> mViews;
private View mConvertView;
private CommonViewHolder(Context context, ViewGroup parent,int layoutId,int position) {
this.mViews = new SparseArray<>();
mConvertView = LayoutInflater.from(context).inflate(layoutId,parent,false);
mConvertView.setTag(this);
}
/**
* 拿到一个ViewHolder对象
* @param context 上下文
* @param convertView 视图view
* @param parent 容器
* @param layoutId 布局layoutID
* @param position 当前索引
* @return
*/
public static CommonViewHolder get(Context context, View convertView,
ViewGroup parent, int layoutId, int position)
{
if (convertView == null)
{
return new CommonViewHolder(context, parent, layoutId, position);
}
return (CommonViewHolder) convertView.getTag();
}
/**
* 通过控件的Id获取对于的控件,如果没有则加入views
* @param viewId
* @return
*/
public <T extends View> T getView(int viewId)
{
View view = mViews.get(viewId);
if (view == null)
{
view = mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
public View getConvertView()
{
return mConvertView;
}
}
第二步抽取Adapter:
/**
*通用Adapter
* Created by lx_yoyo on 2016/8/10.
*/
public abstract class CommonAdapter<T> extends BaseAdapter {
protected LayoutInflater mInflater;
protected Context mContext;
protected List<T> mDatas;
protected final int mItemLayoutId;
public CommonAdapter(Context context, List<T> mDatas, int itemLayoutId)
{
this.mContext = context;
this.mInflater = LayoutInflater.from(mContext);
this.mDatas = mDatas;
this.mItemLayoutId = itemLayoutId;
}
@Override
public int getCount()
{
return mDatas.size();
}
@Override
public T getItem(int position)
{
return mDatas.get(position);
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
final CommonViewHolder viewHolder = getViewHolder(position, convertView,
parent);
convert(viewHolder, getItem(position));
return viewHolder.getConvertView();
}
public abstract void convert(CommonViewHolder helper, T t);
private CommonViewHolder getViewHolder(int position, View convertView,
ViewGroup parent)
{
return CommonViewHolder.get(mContext, convertView, parent, mItemLayoutId,
position);
}
}
第三步就是Activity调用:
......
private List<Bean> mDatas = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView listView = (ListvView)findViewById(R.id.Listview);
listView.setAdapter(new CommonAdapter<Bean>(getApplicationContext(),mDatas,R.layout.list_item) {
@Override
public void convert(CommonViewHolder helper, Joke.ShowapiResBodyBean.ContentlistBean item) {
//在这里就写item中的控件以及赋值
TextView titleText = helper.getView(R.id.text_title);
titleText.setText(item.getTitle());
TextView contentText = helper.getView(R.id.text_content);
contentText.setText(item.getText());
}
} );
}
......
以上就是一个万能适配器了,像CommonAdapter和CommonViewHolder基本上也不需要变动了,一劳永逸。
像上面简单控件赋值的话可以直接写在Activity里面,如比较复杂的item的话单独写个适配器,但不需要再
去继承BaseAdapter了,直接继承CommonAdapter配合CommonViewHolder就可以了。这样使代码量减少了很多。
当然以上代码还可以更简化一点,就是把这些ViewHolder.getView和setText,setImage等方法再一次封装,变成只传递控件Id和对应数据就够了,这样一来我们连类都不需要写了,直接用new对象去写个内部类实现就可以了。
代码如下:
/**
*这里只写文字和图片的,如还需什么的自己去加就可以了
*/
public class CommonViewHolder {
......
/**
* 为TextView设置字符串
*
* @param viewId
* @param text
* @return
*/
public CommonViewHolder setText(int viewId, String text)
{
TextView view = getView(viewId);
view.setText(text);
return this;
}
/**
* 为ImageView设置图片
*
* @param viewId
* @param drawableId
* @return
*/
public CommonViewHolder setImageResource(int viewId, int drawableId)
{
ImageView view = getView(viewId);
view.setImageResource(drawableId);
return this;
}
/**
* 为ImageView设置图片
*
* @param viewId
* @param drawableId
* @return
*/
public CommonViewHolder setImageBitmap(int viewId, Bitmap bm)
{
ImageView view = getView(viewId);
view.setImageBitmap(bm);
return this;
}
/**
* 为ImageView设置图片
*
* @param viewId
* @param drawableId
* @return
*/
public CommonViewHolder setImageByUrl(int viewId, String url)
{
ImageLoader.getInstance(3, Type.LIFO).loadImage(url,
(ImageView) getView(viewId));
return this;
}
......
}
现在在Activity只需要这么写:
......
private List<Bean> mDatas = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView listView = (ListvView)findViewById(R.id.Listview);
listView.setAdapter(new CommonAdapter<Bean>(getApplicationContext(),mDatas,R.layout.list_item) {
@Override
public void convert(CommonViewHolder helper, Bean item) {
//在这里就写item中的控件以及赋值
helper.setText(R.id.id.text_title,item.getTitle())
.setText(R.id.text_content,item.getText);
}
} );
}
......
到此,Android 打造万能的ListView GridView 适配器结束;
源码地址:点击下载万能适配器
谢谢!!!