物尽其用,偷懒有理(来封装一个ListView)

时间:2021-03-08 16:37:31

来深圳一个星期,终于安定下来了,一片新的土地上我准备迎接一个新的开始,刚刚坐在床上想,工作了那么久,却很少有记录的习惯,导致新的东西一直在迭代,旧的事物快被想不起来,真是应了那句老话:茕茕白兔,东走西顾,衣不如新,人不如故。

好了不伤感了,开始今天的主题:ListView;
开始之前先说一点废话,之前带过两个实习生:只知道埋头苦干,做什么都不求甚解,跟刚毕业时候的我真是别无二样,比如,我问他们,你们是怎么理解ListView的? 居然支支吾吾答不上来,我说说我的理解吧,

我觉得得先从字面上解释,ListView就是一个以列表方式呈现的视图,它由一排透明的盒子组成,如果盒子里没有东西,那它就是透明的显示在屏幕上,而至于装什么东西,完全取决于你,装一个文本框,装一张图片,装一个复选框,甚至装一个fragment都随便你,而这些盒子,就是我们说的items,紧接着,我们要考虑一下,怎么装,装的数量,装的东西从哪儿来,于是就用到了适配器,适配器就是帮助你有序的解决这些问题的。

在日常的开发中,ListView基本是最常用的控件之一了,我们经常要写,至于ListView的优化,这里就不多讲了,很多人都能倒背如流了吧?
重点来了,既然ListView每天要用,是不是就会产生很多重复代码?
你在写的时候,有没有想过,把ListView的适配过程封装起来,让代码显得更简洁,自己也少做一点无用功。

反正我想过,先贴一段正常的ListView适配代码,观察一下哪里有封装的余地。

引用 Ctpublic class MyListViewAdapter extends BaseAdapter {
List data = new ArrayList();
Context context;
boolean idRefush = false;

public MyListViewAdapter(List<GiftInfo> data, Context context) {
super();
this.data = data;
this.context = context;
}


public void setData(List<GiftInfo> data) {
if (idRefush) {
this.data.clear();
}
this.data.addAll(data);
notifyDataSetChanged();
}


@Override
public int getCount() {
return data.size();
}

@Override
public Object getItem(int position) {
return data.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.items, parent,
false);
ImageView imageView = (ImageView) view
.findViewById(R.id.imageView1);
TextView textView = (TextView) view.findViewById(R.id.textView1);
TextView remain=(TextView) view.findViewById(R.id.remain);
TextView content=(TextView) view.findViewById(R.id.content);

ViewHolder holder = new ViewHolder(imageView, textView, remain, content);
view.setTag(holder);
}
GiftInfo giftInfo = data.get(position); // 加载文字
ViewHolder holder = (ViewHolder) view.getTag();
holder.textView.setText(giftInfo.getName());
holder.remain.setText(giftInfo.getRemain()+"");
holder.content.setText(giftInfo.getContent());

ImageListener listener = ImageLoader.getImageListener(
holder.imageView,// 加载图片
R.drawable.checkbox_uncheck,
R.drawable.vpi__tab_selected_pressed_holo);
MyApp.loader.get(giftInfo.getIcon(), listener);

return view;
}

public class ViewHolder {
ImageView imageView;
TextView textView,remain,content;



public ViewHolder(ImageView imageView, TextView textView,
TextView remain, TextView content) {
super();
this.imageView = imageView;
this.textView = textView;
this.remain = remain;
this.content = content;
}



public ViewHolder() {
}

}

}rl + Q

看完头昏脑涨有没有,先看看我写的封装类和平时的有什么不同

Ctpublic abstract class AbsBaseAdapter extends BaseAdapter{
private Context context;
private List datas;
private int resid;

public AbsBaseAdapter(Context context, int resid){
this.context = context;
this.resid = resid;
datas = new ArrayList<>();
}

public void setDatas(List<T> datas){
this.datas.clear();
addDatas(datas);
}

public void addDatas(List<T> datas){
this.datas.addAll(datas);
this.notifyDataSetChanged();
}


@Override
public int getCount() {
return datas.size();
}

@Override
public Object getItem(int position) {
return datas.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){
viewHolder = (ViewHolder) convertView.getTag();
} else {
convertView = LayoutInflater.from(context).inflate(resid, null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
}

//从数据源中获得数据,依次放入ViewHodler中的控件里
bindDatas(viewHolder, datas.get(position));
return convertView;
}

public abstract void bindDatas(ViewHolder viewHolder, T data);

/**
* ViewHolder主要是用来缓存布局页面中的子控件,避免下一次使用时还需要findViewById
*/
class ViewHolder{
View layoutView;
Map<Integer, View> mapCache = new HashMap<>();

public ViewHolder(View layoutView) {
this.layoutView = layoutView;
}

public View getView(int id){
View view = null;
if(mapCache.containsKey(id)){
view = mapCache.get(id);
} else {
view = layoutView.findViewById(id);
mapCache.put(id, view);
}
return view;
}
}

}rl + Q

看到了吗?我把我的封装类写成了一个抽象类,还指定泛型为任意,
再看到我在构造方法里放的两个参数:
第一是上下文对象,第二个我放的是你的资源ID,也就是你的items的位置
然后我加了一个setData方法,我们在这个方法里添加和刷新数据

最重要的一步到了,看到了我的抽象方法:bindData()没有?
然后你跟我说说,里面的参数有什么?是什么viewHolder对象和你每一个view的位置?
接下来我们要做的是什么,你可以告诉我吗?
对,我们用一个类去继承我们的封装类,,在构造方法里传进你的资源id,然后复写他的抽象方法,就可以了。
那些listview的优化,你还用去考虑吗?
送佛送到西,贴一个实现的封装的例子,看看什么是简洁代码
Ct`public class MyAdapter extends AbsBaseAdapter{

public MyAdapter(Context context) {
super(context, R.layout.item_layout);
}

@Override
public void bindDatas(ViewHolder viewHolder, NewsEntity data) {
ImageView iv = (ImageView) viewHolder.getView(R.id.iv_id);
iv.setImageResource(R.mipmap.ic_launcher);

TextView tv = (TextView) viewHolder.getView(R.id.tv_id);
tv.setText(data.getTitle());
}

}`rl + Q

这里用到了一点java的继承思想,不知道有人犯迷糊了没有,如果有,欢迎一起讨论,千万别憋着。