黑马程序员技术交流社区
标题:
Android ListView 万能Adapter 减少80%代码 请求置顶
[打印本页]
作者:
小刘123
时间:
2015-9-6 20:24
标题:
Android ListView 万能Adapter 减少80%代码 请求置顶
在我们日常的开发中 避免不了使用listview控件,即使现在 google已经退出recyclerview 很久 ,但是listview一直在我们使用频率最高的列表展示控件,而且我们的使用套路已经模式化了 添加 listview控件-->创建adapter---在adapter里面创建viewholder—>在 adapter getview方法里面进行绑定 给每个控件 赋值。
首先我们按照一般的方式创建listview 设置
public class GenAdapter extends BaseAdapter {
private List<CityModel> mData;
private Context mContext;
public GenAdapter(List<CityModel> mData, Context mContext) {
super();
this.mData = mData;
this.mContext = mContext;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public CityModel getItem(int pos) {
return mData.get(pos);
}
@Override
public long getItemId(int pos) {
return pos;
}
@Override
public View getView(int pos, View convertView, ViewGroup arg2) {
CityModel model = mData.get(pos);
View view = null;
ViewHolder holder = null;
if (convertView == null) {
view = View.inflate(mContext, R.layout.item_city, null);
holder = new ViewHolder();
holder.tvCityName = (TextView) view.findViewById(R.id.tvCityName);
holder.tvCityCode = (TextView) view.findViewById(R.id.tvCityCode);
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder) view.getTag();
}
holder.tvCityName.setText(model.cityName);
holder.tvCityCode.setText(model.cityCode);
return view;
}
private static class ViewHolder {
public TextView tvCityName, tvCityCode;
}
}
复制代码
如果我们写一个adapter 我们不会感觉 任何问题 但是如果 在app中经常出现呢??是不是还需要重复的写 这些呢?
getCount()
getItem(int pos)
getItemId(int pos) 这三个方法很容易抽取出来 。
我们怎么处理ViewHolder 跟
getView(int pos, View convertView, ViewGroup arg2) 呢?每次都需要写吗?
基于这些问题 有这一种方式,我们把ViewHolder独立出来 使用Map<int,View> 来保存 ConverView里面的控件
最终写的代码是这样的:
public class ViewHolder {
/**
* listview 一个item的 所包含的view 都保存在里面
*/
private SparseArray<View> mViews;
private Context mContext;
private int mPostion;
private View mConvertView;
private ViewHolder(Context context, ViewGroup parent, int layoutId,
int postion) {
this.mContext = context;
this.mPostion = postion;
this.mViews = new SparseArray<View>();
mConvertView = LayoutInflater.from(mContext).inflate(layoutId, parent,
false);
mConvertView.setTag(this);
}
public static ViewHolder get(Context context, View convertView,
ViewGroup parent, int layoutId, int postion) {
if (convertView == null) {
return new ViewHolder(context, parent, layoutId, postion);
} else {
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.mPostion = postion;
return holder;
}
}
public View getConvertView() {
return mConvertView;
}
/**
* 根据资源id获取 控件
*
* @param viewId
* @return
*/
public <T extends View> T getView(int viewId) {
View v = mViews.get(viewId);
if (v == null) {
v = mConvertView.findViewById(viewId);
mViews.put(viewId, v);
}
return (T) v;
}
}
复制代码
这样我们就完成了将ViewHolder 抽取出来了。这样还不是最 简洁 我们在处理一下 Adapter 首先 我们已经 知道 需要把
getCount()
getItem(int pos)
getItemId(int pos) 抽取到父类中了 因此我们需要 使用泛型解决。 另外在 LIstView日常使用的时候我们经常需要 切换数据源(刷新) 或者增加(分页)因此我们把 这两个方法都抽取到父类 最终的实现 就是这样的:
public abstract class CommonAdapter<T> extends BaseAdapter {
protected List<T> mData;
protected Context mContext;
protected LayoutInflater mInflater;
public CommonAdapter(Context mContext) {
super();
mData = new ArrayList<T>();
this.mContext = mContext;
this.mInflater = LayoutInflater.from(mContext);
}
@Override
public int getCount() {
return mData!=null?mData.size():0;
}
@Override
public T getItem(int position) {
return mData.get(position);
}
/**
* 添加 数据集合
* @param data
*/
public void addData(List<T> data) {
if (mData == null) {
mData = new ArrayList<T>();
}
mData.addAll(data);
notifyDataSetChanged();
}
/**
* 添加一条数据
* @param t
*/
public void addItem(T t) {
if (mData == null) {
mData = new ArrayList<T>();
}
mData.add(t);
notifyDataSetChanged();
}
/**
* 添加指定位置的一条数据
* @param pos
* @param obj
*/
public void addItem(int pos, T obj) {
if (mData == null) {
mData = new ArrayList<T>();
}
mData.add(pos, obj);
notifyDataSetChanged();
}
/**
* 移除一个item
*
* @param obj
*/
public void removeItem(T obj) {
mData.remove(obj);
notifyDataSetChanged();
}
/**
* 清空数据
*/
public void clear() {
if (mData != null) {
mData.clear();
}
notifyDataSetChanged();
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = ViewHolder.get(mContext, convertView, parent,
getLayoutId(), position);
convert(holder, getItem(position));
return holder.getConvertView();
}
/**
* 将数据赋值到 ui控件上
*
* @param holder
* @param t
*/
public abstract void convert(ViewHolder holder, T t);
/**
* item的布局id
*
* @return
*/
public abstract int getLayoutId();
}
复制代码
好了 我们先写一个例子 :
public class FastAdapter extends CommonAdapter<CityModel> {
public FastAdapter(Context mContext) {
super(mContext);
}
@Override
public void convert(ViewHolder holder, CityModel t) {
holder.setText(R.id.tvCityName, t.cityName);
holder.setText(R.id.tvCityCode, t.cityCode);
}
@Override
public int getLayoutId() {
return R.layout.item_city;
}
}
复制代码
FastAdapter跟GenAdapter 实现了相同的功能 或者说 比后者功能更强大,但是代码明显减少。如果 itenVIew中的控件再多一些的画 就会明显看出来了。
列子 附在附件 两个类的代码 好好研究是 确实能减轻自己不少 压力 提高代码的质量
注意 :不好意思 刚才 代码 编码是gbk的 各位注意了
DemoList.zip
2015-9-6 20:23 上传
点击文件名下载附件
1.07 MB, 下载次数: 133
作者:
淡忘初学者
时间:
2015-9-6 20:38
还没学,但不过感觉好高级
作者:
云沾衣。
时间:
2015-9-6 21:30
不明觉厉呢。
作者:
l631356126
时间:
2015-9-6 21:32
略高端,大神自己写的吗
作者:
不想睡
时间:
2015-9-6 21:47
虽然现在看不懂,但以后应该能用上,先收藏了
作者:
keto
时间:
2015-9-6 22:23
已阅~~~~
作者:
小刘123
时间:
2015-9-8 10:08
不要沉。。。啊
作者:
guoqule
时间:
2015-9-24 23:45
非常好的容器,做下拉菜单的神器
作者:
1384588560
时间:
2015-9-25 00:06
我去 这么多
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2