在Android中ListView,Spinner,Gallery等控件是经常会用到的,而要用这些控件,就离不开Adapter(适配器),它的主要功能是将数据转化成要在ListView中要显示的样式。对于比较简单的样式,使用系统已经实现好的类,如ArrayAdapter,SimpleAdapter等就可以了,但对于比较复杂的样式,通常会需要自己写一个适配器(通常继承BaseAdapter类),下面就针对自己写的Adapter来进行一番分析。
一、BaseAdapter的结构
BaseAdapter作为基础适配器,是其他适配器的父类,我在Android的Api文档中找到了它的子类,可以看到这些就是我们常用的一些简单适配器。
下面是继承BaseAdapter类的默认方法,用来给大家看一下BaseAdapter的类结构吧
public class MyAdapter 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;
}
}
二、运行机制
以ListView为例,在要绘制ListView的时候,首先调用getCount()方法来取得要绘制的ListView的行数,也就是ListView的长度。然后再调用getView()方法来绘制每一行,它有三个参数,第一个是在ListView中位置position,第二个参数是传入的view,convertView,在当ListView滚动时,消失不见的view会被系统回收,作为绘制新出现的一行的参数,第三个参数是viewGroup,也就是它的父控件组。另外还有两个比较重要的方法是getItem()和getItemId(),在取得ListView的某一个元素的时候会有用到。
这里再重点说一下getView()方法,这个是BaseAdapter中最重要的方法,因为在这个方法里面,实现了它的主要功能,也就是将数据转化为控件可用。下面是最简单的一种写法,就是获取到控件,然后进行相应的设置,然后返回,但是这有个问题,就是每一行都需要绘制一次,当行数很多的时候,就会造成极大的内存消耗,这显然不是我们想要的,所以我们就需要对它进行优化。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
TextView catalog = (TextView) convertView.findViewById(R.id.catalog);
TextView title = (TextView) convertView.findViewById(R.id.title);
catalog.setText("I'm Catalog");
title.setText("I'm Title");
return convertView;
}
三、优化
1.上面说到了convertView是系统回收的隐藏的行,那很明显的一种改进方法就是利用这个convertView作为缓存来实现优化。对比前面的代码,会发现实际上只是加了一个convertView!=null,但却有很大的不同,只有在convertView为空的时候才去绘制,如果不为空,只需要获取到要设置的控件,然后加以修改就可以了。实际上加了这一句之后,所需要绘制的行数等于一屏幕最多显示的行数,其它的都是从之前的行获取,大大减少了内存消耗。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView != null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item,
null);
}
TextView catalog = (TextView) convertView.findViewById(R.id.catalog);
TextView title = (TextView) convertView.findViewById(R.id.title);
catalog.setText("I'm Catalog");
title.setText("I'm Title");
return convertView;
}
2.现在再来考虑一个问题,就是如果当布局比较复杂的时候,调用findViewById()这个方法需要的内存也会有所增加,为了减少这部分的内存消耗,就有人想到了一种方法,构造一个静态类来缓存控件,然后用setTag()方法,保存在这一行里,这样就不需要重复的调用getViewById()这个方法了
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView != null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item,
null);
holder.catalog = (TextView) convertView.findViewById(R.id.catalog);
holder.title = (TextView) convertView.findViewById(R.id.title);
convertView.setTag(holder);
}else {
holder=(ViewHolder) convertView.getTag();
}
holder.catalog.setText("I'm Catalog");
holder.title.setText("I'm Title");
return convertView;
}
final static class ViewHolder {
TextView catalog;
TextView title;
}