ListView 是一个挺难用的控件,为什么这样说,因为他有很多可以优化操作的细节,运行效率是 ListView 的一个很重要的指标。当我们对 ListView 不进行任何优化时,在执行 Adapter 的 getView() 方法时,每次都将布局重新加载了一遍。代码如下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Xxxx xxxx = getItem(position); // 获取实例(Xxxx为自定义布局)
View view = LayoutInflater.from(getContext()).inflate(resourceId,null);
***
***
return view;
}
那要怎样对它进行优化呢?
方法一:
getView() 方法中有一个 convertView 参数,这个参数用于将之前加载好的布局进行缓存,以便之后可以进行重用。修改代码如下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Xxxx xxxx = getItem(position);
View view; if (convertView == null) {
view=LayoutInflater.from(getContext()).inflate(resourceId,null);
} else {
view = convertView;
}
***
***
return view;
}
在 getView()方法中进行判断,如果 convertView为空,则使用 LayoutInflater 去加载布局,如果不为空则对 convertView进行重用。这样便提高了 ListView 的运行效率。
方法二:
虽然通过 contentView 参数实现了复用,不会重复去加载布局, 但是每次在 getView() 方法中还是会调用 View 的 findViewById() 方法来获取一次控件的实例,怎样优化,代码如下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Xxxx xxxx = getItem(position);
View view;
ViewHolder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(getContext()).inflate(resourceId,null);
viewHolder = new ViewHolder();
viewHolder.*** = *** // 通过 findViewById()方法来获取控件实例
***
view.setTag(viewHolder); // 将ViewHolder存储在View中
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag(); // 把 ViewHolder重新取出
}
viewHolder.*** = ***
return view;
}
//内部类,对控件实例缓存
class ViewHolder {
***
//布局里面的控件内容
}
当 convertView为空 的时候,创建一个 ViewHolder对象,并将控件的实例都存放在 ViewHolder里,然后调用 View 的 setTag()方法,将 ViewHolder对象存储在 View中。当 convertView不为空的时候则调用 View的 getTag()方法,把 ViewHolder重新取出。这样所有控件的实例都缓存在了 ViewHolder 里,没有必要每次都通过 findViewById()方法来获取控件实例了。