ListView基本使用

来源:互联网 发布:知乎是什么类型的网站 编辑:程序博客网 时间:2024/06/16 14:12

珍惜作者劳动成果 转载请注明出处

  学过ListView的人都知道, 它在Android学习中有着举足轻重的地位, 虽然现在有了RecyClerView来替代ListView, 但是对于我们初学者来说, 了解和使用ListView还是非常重要的!!!
  我们应该知道, 显示复杂内容的控件一般会有一个Adapter来控制它的显示. 这其实就是我们平常所说的MVC设计模式. Adapter就扮演了Controller的角色.

  在具体实现之前我们要从大方向上来了解一下ListView的实现机制.

ListView是用来显示数据的控件, 在xml布局文件中存放(当然也可以用Java代码实现, 就不要这么钻牛角尖了^v^), 所以它需要有数据源, 才能显示数据, 但是它也需要知道我们的数据怎样展示在手机上, 这就用到了我们的Adapter. 好,先简单介绍到这儿, 后面会有详细的阐述.

实现ListView的几种简单的方式

  接下来, 我先介绍几种实现ListView非常简单的方式, 不过这几种在我们后来的工作, 项目中几乎不用, 所以我也不做过多的解释.

直接在XML文件中指定数据源.

<ListView    android:entries="@array/entry"        ... />

简单到没朋友, 后期几乎没用

ArrayAdapter的实现方式

ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,  list);ListView listView = (ListView) findViewById(R.id.main_listview);listView.setAdapter(adapter);

不解释

SimpleAdapter实现方式

它虽然叫简单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;   }});

使用BaseAdapter实现ListView

我们现在前面做理论说明, 整理好后代码在最后贴出

简单介绍

首先我们写个类(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;}

ListView优化方案

1, listView布局的高度必须是定值或match_parent    先去取第1个条目的高度和第2个条目想加,...    计算自身的高度, 所以不要使用wrap_content2, convertView的复用3, 减少findViewById的使用次数

尽量减少自己去控制数据源!!(符合MVC设计模式)

贴出代码, 一般一个完整的Adapter就是下面的格式

public class MyAdapter extends BaseAdapter{   private final LayoutInflater inflater;   private Context context;   private List<Entry> list;   public MyAdapter(Context context, List<Entry> 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));       }   }}

到目前为止我们可以解决显示本地图片问题, 但是我们加载网络数据(尤其是图片)还是有问题的

解决item显示图片错位的问题和图片缓存问题 (Lru算法缓存机制)

细心的朋友会发现, 在上面的代码中, 有下面一句 :

ImageUtil.loadImage(holder.image, "http://tnfs.tngou.net/image" + entry.getImgURL());

里面的代码已经解决了这个问题, 我将会把源码上传到云盘供大家下载, 我在源码中已经加上了注释 https://yunpan.cn/cMzI4y8SykZrR 访问密码 e1dc

自己封装BaseAdapter

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<D> list;    public CommonAdapter(Context context, int layoutId, List<D> 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();    }}
0 0