ListView基本使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013144863/article/details/52439238

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

  学过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_content
2, 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();
    }
}
阅读更多

没有更多推荐了,返回首页