珍惜作者劳动成果 转载请注明出处
学过ListView的人都知道, 它在Android学习中有着举足轻重的地位, 虽然现在有了RecyClerView来替代ListView, 但是对于我们初学者来说, 了解和使用ListView还是非常重要的!!!
我们应该知道, 显示复杂内容的控件一般会有一个Adapter来控制它的显示. 这其实就是我们平常所说的MVC设计模式. Adapter就扮演了Controller的角色.
在具体实现之前我们要从大方向上来了解一下ListView的实现机制.
ListView是用来显示数据的控件, 在xml布局文件中存放(当然也可以用Java代码实现, 就不要这么钻牛角尖了^v^), 所以它需要有数据源, 才能显示数据, 但是它也需要知道我们的数据怎样展示在手机上, 这就用到了我们的Adapter. 好,先简单介绍到这儿, 后面会有详细的阐述.
接下来, 我先介绍几种实现ListView非常简单的方式, 不过这几种在我们后来的工作, 项目中几乎不用, 所以我也不做过多的解释.
<ListView
android:entries="@array/entry"
... />
简单到没朋友, 后期几乎没用
ArrayAdapter adapter =
new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1,
list);
ListView listView = (ListView) findViewById(R.id.main_listview);
listView.setAdapter(adapter);
不解释
它虽然叫简单Adapter, 但是还是比ArrayAdapter复杂点, 灵活性要高些,因为用到机率也不大, 所以不解释了, 自己可以看看使用方式
//只能用id或本地
SimpleAdapter adapter = new SimpleAdapter(this, list,R.layout.item,
new String[]{"title", "img"},
new int[]{R.id.item_tv, R.id.item_iv}
);
adapter.setViewBinder(new SimpleAdapter.ViewBinder() {
@Override//返回值: 是否绑定完成
public boolean setViewValue(View view, Object data, String textRepresentation) {
switch (view.getId()){
//绑定ImageView
case R.id.item_iv:
ImageView imageView = (ImageView) view;
String url = (String) data;
new ImageLoader(imageView).execute(url);
return true;
}
return false;
}
});
我们现在前面做理论说明, 整理好后代码在最后贴出
首先我们写个类(MyAdapter) extents BaseAdapter, 因为BaseAdapter为抽象类, 所以需要实现父类的四个方法
@Override//返回数据的数量
public int getCount() {
return 0;
}
@Override//返回当前数据的对象, 参数: 位置
public Object getItem(int position) {
return null;
}
@Override//返回当前数据对象的id(如果没有可以直接返回position) //参数: 位置
public long getItemId(int position) {
return 0;
}
/*
在这里非常重要的方法, 每次item(数据项)显示在手机上时都会调用一次getView, 也就是说它返回的View就是每次显示在手机上的item
*/
@Override//参数: 位置, 复用的View(一边item出去后,再次调用时会传入该item), 父控件
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
1, listView布局的高度必须是定值或match_parent
先去取第1个条目的高度和第2个条目想加,...
计算自身的高度, 所以不要使用wrap_content
2, convertView的复用
3, 减少findViewById的使用次数
尽量减少自己去控制数据源!!(符合MVC设计模式)
贴出代码, 一般一个完整的Adapter就是下面的格式
public class MyAdapter extends BaseAdapter{
private final LayoutInflater inflater;
private Context context;
private List list;
public MyAdapter(Context context, List list) {
this.context = context;
this.list = list;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override //位置 //重复利用的控件 //父控件
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.item, parent, false);
convertView.setTag(new ViewHolder(convertView));
}
ViewHolder holder = (ViewHolder) convertView.getTag();
Entry entry = list.get(position);
ImageUtil.loadImage(holder.image, "http://tnfs.tngou.net/image" + entry.getImgURL());
return convertView;
}
//批量添加
public void addAll(Collection extends Entry> collection){
list.addAll(collection);
notifyDataSetChanged();
}
//数据清理
public void clear() {
list.clear();
notifyDataSetChanged();
}
//就是View的持有
public static class ViewHolder {
private final TextView text;
private final ImageView image;
public ViewHolder(View itemView) {
text = ((TextView) itemView.findViewById(R.id.item_tv));
image = ((ImageView) itemView.findViewById(R.id.item_iv));
}
}
}
到目前为止我们可以解决显示本地图片问题, 但是我们加载网络数据(尤其是图片)还是有问题的
细心的朋友会发现, 在上面的代码中, 有下面一句 :
ImageUtil.loadImage(holder.image, "http://tnfs.tngou.net/image" + entry.getImgURL());
里面的代码已经解决了这个问题, 我将会把源码上传到云盘供大家下载, 我在源码中已经加上了注释 https://yunpan.cn/cMzI4y8SykZrR 访问密码 e1dc
BaseAdapter中有很多代码都可以复用, 所以我们写一个通用的Adapter
package com.lulu.day26_listview;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.net.IDN;
import java.util.Collection;
import java.util.List;
/**
* Created by Lulu on 2016/9/2.
*/
public abstract class CommonAdapter<D, VH extends CommonAdapter.ViewHolder> extends BaseAdapter {
private final LayoutInflater inflater;
private Context context;
private int layoutId;
//数据源
private List list;
public CommonAdapter(Context context, int layoutId, List list) {
this.context = context;
this.layoutId = layoutId;
this.list = list;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return list.size();
}
@Override
public D getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
D d = list.get(position);
Class> aClass = (Class>) d.getClass();
Field id = null;
try {
id = aClass.getField("id");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
if (id == null) {
try {
id = aClass.getDeclaredField("id");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
if (id != null) {
try {
return (long) id.get(d);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
Method getId = null;
try {
getId = aClass.getMethod("getId");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
if (getId == null) {
try {
getId = aClass.getDeclaredMethod("getId");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
if (getId != null) {
try {
return (long) getId.invoke(id);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(layoutId, parent, false);
//如何获取Vh怎样获取它的子类呢?
Class type = (Class) ((ParameterizedType) getClass()
.getGenericSuperclass())
.getActualTypeArguments()[0];
try {
Constructor constructor = type.getConstructor(View.class);
Object o = constructor.newInstance(convertView);
convertView.setTag(o);
} catch (Exception e) {
e.printStackTrace();
}
}
onBindView(list.get(position), (VH) convertView.getTag());
return convertView;
}
public abstract void onBindView(D data, VH holder);
public static class ViewHolder {
private View itemView;
public ViewHolder(View itemView) {
this.itemView = itemView;
}
}
public void addAll(Collection extends D> collection) {
list.addAll(collection);
notifyDataSetChanged();
}
public void clear() {
list.clear();
notifyDataSetChanged();
}
public void add(D d) {
list.add(d);
notifyDataSetChanged();
}
public void add(int index, D d) {
list.add(index, d);
notifyDataSetChanged();
}
public void remove (D d) {
list.remove(d);
notifyDataSetInvalidated();
}
public void remove (int index) {
list.remove(index);
notifyDataSetInvalidated();
}
}