Android实现一个简单的自定义适配器

经常面试会被问以下的面试题:ListView的优化方案 答:

(1)如果自定义适配器,那么在getView方法中要考虑方法传进来的参数convertView是否为null,如果为null就创建convertView并返回,如果不为null则直接使用。在这个方法中尽可能少创建view。

(2)给convertView设置tag(setTag()),传入一个viewHolder对象,用于缓存要显示的数据,可以达到图像数据异步加载的效果。

(3)如果listview需要显示的item很多,就要考虑分页加载。比如一共要显示100条或者更多的时候,我们可以考虑先加载20条,等用户拉到列表底部的时候再去加载接下来的20条。


在安卓开发的过程中,我们经常会用到ListView控件,在ListView中也会有一个个的item,我们在使用的时候需要对其进行数据的适配,那么Android系统提供了一系列的适配器(Adapter)来实现数据的适配。又已知我常用的适配器包括:BaseAdapter、SimpleAdapter、ArrayAdapter。其中后两项SimpleAdapter和ArrayAdapter都是BaseAdapter的子类,相当于是Android提供的两种可以直接来用的适配器,在使用的时候我们可以根据自己的需要传入参数即可。那么其实在实际开发的时候,我们用的更多的是BaseAdapter这样一个适配器来做一个“自定义”的适配器。那么接下来,我会用一个小小的例子来介绍使用BaseAdapter。

1.首先我们需要用来写一个实体类,这个实体类用来封装我们需要适配显示的信息的集合。

比如我这里定义了一个联系人的实体类(类的名字有点拼音化,不是很规范,但是不影响效果),然后我这里定义了三个String类型的变量:姓名、学号、简介。然后下面是getters和setters方法还有一个“满参”构造函数,还有一个无参构造函数。

[java] view plain copy print ?
  1. public class LianxirenBean {  
  2.     private String name;  
  3.     private String number;  
  4.     private String introduce;  
  5.   
  6.     public String getName() {  
  7.         return name;  
  8.     }  
  9.   
  10.     public void setName(String name) {  
  11.         this.name = name;  
  12.     }  
  13.   
  14.     public String getNumber() {  
  15.         return number;  
  16.     }  
  17.   
  18.     public void setNumber(String number) {  
  19.         this.number = number;  
  20.     }  
  21.   
  22.     public String getIntroduce() {  
  23.         return introduce;  
  24.     }  
  25.   
  26.     public void setIntroduce(String introduce) {  
  27.         this.introduce = introduce;  
  28.     }  
  29.   
  30.     public LianxirenBean() {  
  31.         super();  
  32.     }  
  33.   
  34.     public LianxirenBean(String name, String number, String introduce) {  
  35.         super();  
  36.         this.name = name;  
  37.         this.number = number;  
  38.         this.introduce = introduce;  
  39.     }  
  40.   
  41. }  
public class LianxirenBean {    private String name;    private String number;    private String introduce;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getNumber() {        return number;    }    public void setNumber(String number) {        this.number = number;    }    public String getIntroduce() {        return introduce;    }    public void setIntroduce(String introduce) {        this.introduce = introduce;    }    public LianxirenBean() {        super();    }    public LianxirenBean(String name, String number, String introduce) {        super();        this.name = name;        this.number = number;        this.introduce = introduce;    }}
2.其次,我就需要新建一个类(LianxirenAdapter)继承BaseAdapter。

然后我先随意建一个类继承BaseAdapter然后看看里面都有什么

[java] view plain copy print ?
  1. import android.view.View;  
  2. import android.view.ViewGroup;  
  3. import android.widget.BaseAdapter;  
  4.   
  5. public class TestAdapter extends BaseAdapter {  
  6.   
  7.     @Override  
  8.     public int getCount() {  
  9.         // TODO Auto-generated method stub  
  10.         return 0;  
  11.     }  
  12.   
  13.     @Override  
  14.     public Object getItem(int position) {  
  15.         // TODO Auto-generated method stub  
  16.         return null;  
  17.     }  
  18.   
  19.     @Override  
  20.     public long getItemId(int position) {  
  21.         // TODO Auto-generated method stub  
  22.         return 0;  
  23.     }  
  24.   
  25.     @Override  
  26.     public View getView(int position, View convertView, ViewGroup parent) {  
  27.         // TODO Auto-generated method stub  
  28.         return null;  
  29.     }  
  30.   
  31. }  
import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;public class TestAdapter extends BaseAdapter {    @Override    public int getCount() {        // TODO Auto-generated method stub        return 0;    }    @Override    public Object getItem(int position) {        // TODO Auto-generated method stub        return null;    }    @Override    public long getItemId(int position) {        // TODO Auto-generated method stub        return 0;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        // TODO Auto-generated method stub        return null;    }}
可以看出来,这里因为继承了BaseAdapter,那么就要实现四个方法:getCount()、getItem()、getItemId()和getView()。

显然,

getCount()方法是要返回ListView里面所有的item子项的个数,因为ListView里面是有很多个item子项需要被适配的,而且我上面已经定义好了一个实体类LianxirenBean用于封装每一个item子项内部需要适配的内容的一个集合,换句话说,每一个实体,就是一个完整的item里面所要适配的所有内容,那么我们又已知,一个ListView不一定只会有一个item,那么显然,我们需要在Adapter里面定义一个泛型为LianxirenBean的一个List,用于表示所有的item子项。即:private List lxrs; 那么定义了之后,显然在getCount()方法下面,就要return lxrs.size();

getItem()方法是要返回每一个item子项,已知我们已经定义了一个泛型为LianxirenBean的List,那么我们如果是要得到每一个子项的话,我们就要用到getposition()方法用于动态的获得每一个item,即这里我们写:return lxrs.get(position);

getItemId()方法是要返回每个item子项的Id,显然我们这里可以直接写return position;即可。
如果说实现前面的三个方法只是做了准备工作了的话,那么显然getView方法就是真正的重头戏了。也就是在getView方法里面我们就要完成和ListView里面的每一个item子项的适配工作。那么接下来我就会用一个完整的代码来讲解这个部分怎样写,还有一个简单的Adapter里面所必须要写的内容。

[java] view plain copy print ?
  1. import java.util.List;  
  2.   
  3. import com.example.mynote.R;  
  4. import android.content.Context;  
  5. import android.view.LayoutInflater;  
  6. import android.view.View;  
  7. import android.view.ViewGroup;  
  8. import android.widget.BaseAdapter;  
  9. import android.widget.TextView;  
  10. import dxxy_swy_Bean.LianxirenBean;  
  11.   
  12. public class LianxirenAdapter extends BaseAdapter {  
  13.       
  14.     private List lxrs;  
  15.     private Context ctx;  
  16.     private LayoutInflater mInflater;  
  17.       
  18.     public LianxirenAdapter(Context context, List lxrs) {  
  19.         ctx = context;  
  20.         this.lxrs = lxrs;  
  21.         mInflater = LayoutInflater.from(context);  
  22.     }  
  23.   
  24.     @Override  
  25.     public int getCount() {  
  26.         // TODO Auto-generated method stub  
  27.         return lxrs.size();  
  28.     }  
  29.   
  30.     @Override  
  31.     public Object getItem(int position) {  
  32.         // TODO Auto-generated method stub  
  33.         return lxrs.get(position);  
  34.     }  
  35.   
  36.     @Override  
  37.     public long getItemId(int position) {  
  38.         // TODO Auto-generated method stub  
  39.         return position;  
  40.     }  
  41.     @Override  
  42.     public View getView(int position, View convertView, ViewGroup parent) {  
  43.         // TODO Auto-generated method stub  
  44.         LianxirenBean lxr = lxrs.get(position);  
  45.         ViewHolder viewHolder = null;  
  46.         if (convertView == null) {  
  47.             convertView = mInflater.inflate(R.layout.lianxiren_item, null);  
  48.             viewHolder = new ViewHolder();  
  49.             viewHolder.name = (TextView) convertView.findViewById(R.id.tv_name);  
  50.             convertView.setTag(viewHolder);  
  51.         } else {  
  52.             viewHolder = (ViewHolder) convertView.getTag();  
  53.         }  
  54.         viewHolder.name.setText(lxr.getName());  
  55.         return convertView;  
  56.     }  
  57.   
  58.     static class ViewHolder {  
  59.         public TextView name;  
  60.         public TextView number;  
  61.         public TextView introduce;  
  62.     }  
  63. }  
import java.util.List;import com.example.mynote.R;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;import dxxy_swy_Bean.LianxirenBean;public class LianxirenAdapter extends BaseAdapter {    private List lxrs;    private Context ctx;    private LayoutInflater mInflater;    public LianxirenAdapter(Context context, List lxrs) {        ctx = context;        this.lxrs = lxrs;        mInflater = LayoutInflater.from(context);    }    @Override    public int getCount() {        // TODO Auto-generated method stub        return lxrs.size();    }    @Override    public Object getItem(int position) {        // TODO Auto-generated method stub        return lxrs.get(position);    }    @Override    public long getItemId(int position) {        // TODO Auto-generated method stub        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        // TODO Auto-generated method stub        LianxirenBean lxr = lxrs.get(position);        ViewHolder viewHolder = null;        if (convertView == null) {            convertView = mInflater.inflate(R.layout.lianxiren_item, null);            viewHolder = new ViewHolder();            viewHolder.name = (TextView) convertView.findViewById(R.id.tv_name);            convertView.setTag(viewHolder);        } else {            viewHolder = (ViewHolder) convertView.getTag();        }        viewHolder.name.setText(lxr.getName());        return convertView;    }    static class ViewHolder {        public TextView name;        public TextView number;        public TextView introduce;    }}
上面的代码里边,我们首先是先写了Adapter的一个构造方法,这是因为我们要在实现逻辑的Activity里面获得适配器的对象,并且还要对适配器做初始化,那么适配器的对象就必须要实现适配器的构造方法。只有这样才能够真正的完成适配器的初始化,才能够在Activity中使用适配器。

我们这个Adapter的构造方法中有两个参数:Context(上下文,这个我是一般理解为“在哪个界面做适配”)、第二个参数是那个泛型为LianxirenBean的List的对象,这个我的理解是所需要适配的内容。

顺带的我在这里表达一下我对适配器这个概念的个人理解:所谓适配,我们首先需要知道我们在哪里适配(Context),还需要知道我们适配的内容是什么(Listlxrs),那么因为适配的内容是需要适配到每一个的item之中

那么针对item而言显然又有几个东西是必须要知道的:1.item的布局、2.item里面都有什么控件需要做适配、3.每个控件对应的都需要适配什么内容?

那么很显然,这些疑问是需要在getView()方法里面得到解决的。那么就来看getView方法。

在此之前我们先考虑一个问题,在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建。解决这个问题可见,我们是利用了ViewHolder方法,这是因为ViewHolder在适配器里,可以在listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能。

在getView()方法中,我们首先定义了一个LianxirenBean实体类的一个对象,初始化的值是lxrs.getposition(),又因为上面实现的第二个方法:getItem()的返回值刚好也是lxrs.getposition(),那么也就是说每一个实体就是对应着每一个item子项,显然这跟我们上面说的是符合的。

然后初始化了一个ViewHolder的对象,初始值为空。可知在文件的最下边,我们定义了一个ViewHolder类,里面放着的是三个TextView属性的变量,刚好一方面对应着我们的实体类的三个属性,同时这个也是我们的每一个的item布局文件里面的三个控件的属性,那么显然,我们是需要对这三个变量进行绑定控件实例化。(注:我这个因为是只需要显示联系人的姓名,所以后边的学号和简介都没有做适配,对应的也没有获得实例)

[java] view plain copy print ?
  1. if (convertView == null) {  
  2.             convertView = mInflater.inflate(R.layout.lianxiren_item, null);  
  3.             viewHolder = new ViewHolder();  
  4.             viewHolder.name = (TextView) convertView.findViewById(R.id.tv_name);  
  5.             convertView.setTag(viewHolder);  
  6.         } else {  
  7.             viewHolder = (ViewHolder) convertView.getTag();  
  8.         }  
  9.         viewHolder.name.setText(lxr.getName());  
  10.         return convertView;  
if (convertView == null) {            convertView = mInflater.inflate(R.layout.lianxiren_item, null);            viewHolder = new ViewHolder();            viewHolder.name = (TextView) convertView.findViewById(R.id.tv_name);            convertView.setTag(viewHolder);        } else {            viewHolder = (ViewHolder) convertView.getTag();        }        viewHolder.name.setText(lxr.getName());        return convertView;
这部分的代码就是完成我上面说过的三个疑问: 1.item的布局、2.item里面都有什么控件需要做适配、3.每个控件对应的都需要适配什么内容?

到此的话,一个基本的Adapter就完成了,那么也只是把适配器的部分完成了,我们同样需要在Activity中获得适配器的对象,然后为我们的ListView设置适配器才是真正完成了适配。

在Activity代码中,我把主要的逻辑代码给出

1.定义泛型为LianxirenBean的List的对象

private List lxrs = new ArrayList();

2.定义适配器对象,并实例化适配器

private LianxirenAdapter lxrAdapter;

lxrAdapter = new LianxirenAdapter(context, lxrs);

3.获得ListView的实例化并且给ListView绑定适配器

private ListView lianxiren_list;

lianxiren_list = (ListView) view.findViewById(R.id.lianxiren_list);

lianxiren_list.setAdapter(lxrAdapter);

4.给lxrs赋值(赋值的内容就是设置适配的内容,我这里是一个数据库查询语句)

private LianxirenOperator lxrOperator;

lxrOperator = new LianxirenOperator(context);

lxrs = lxrOperator.queryMany();

[java] view plain copy print ?
  1. // 查询所有的联系人信息  
  2.     public List queryMany() {  
  3.         ArrayList lxrs = new ArrayList();  
  4.         Cursor c = db.rawQuery(”select * from lxrData”null);  
  5.         while (c.moveToNext()) {  
  6.             LianxirenBean lxr = new LianxirenBean();  
  7.             lxr.setName(c.getString(0));  
  8.             lxr.setNumber(c.getString(1));  
  9.             lxr.setIntroduce(c.getString(2));  
  10.             lxrs.add(lxr);  
  11.         }  
  12.         c.close();  
  13.         return lxrs;  
  14.     }  
// 查询所有的联系人信息 
public List queryMany() {
ArrayList lxrs = new ArrayList();
Cursor c = db.rawQuery("select * from lxrData", null);
while (c.moveToNext()) {
LianxirenBean lxr = new LianxirenBean();
lxr.setName(c.getString(0));
lxr.setNumber(c.getString(1));
lxr.setIntroduce(c.getString(2));
lxrs.add(lxr);
}
c.close();
return lxrs;
}
至此的话,一个基本的自定义的适配器就基本实现功能了
然后,可能会因为写的时间比较赶,然后在某些细节就会避免不聊有忽略的问题,那么如果有对这里面的代码有没有理解的或者是还有问题的话,可以在评论区留言,笔者会尽自己所能回答问题。

更多相关文章

  1. Android 中自定义属性(attr.xml,TypedArray)的使用!
  2. Android 自定义view组件
  3. Android 通用获取Ip的方法(判断手机是否联网的方法)!!!
  4. Android获取音视频原始流数据方法详解
  5. 【Android】Android插件开发 —— 打开插件的Activity(Hook系统方
  6. Android任务切换方法

随机推荐

  1. Android(安卓)Studio中使用NDK
  2. android中的Bitmap
  3. android shareperfence的存储更改与读取
  4. android UI 小知识点
  5. Android(安卓)ADB(Android(安卓)Debug Bri
  6. RelativeLayout
  7. ListView中添加Button后,Button的点击事件
  8. Android(安卓)5.0 API 的变化——开发人
  9. Android(安卓)微信/支付宝 h5调原生支付
  10. ExpandableListView设置选中child的背景