ListView的优化
public class Adapter extends ArrayAdapter<Fruit> { private int resource = 0; public Adapter(@NonNull Context context, int resource, @NonNull List<Fruit> objects) { super(context, resource, objects); this.resource = resource; } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { Fruit fruit = getItem(position); View view = LayoutInflater.from(getContext()).inflate(resource, parent, false); AppCompatImageView fruitImage = view.findViewById(R.id.fruit_image); AppCompatTextView fruitName = view.findViewById(R.id.fruit_name); fruitImage.setImageResource(fruit.getImageId()); fruitName.setText(fruit.getName()); return view; } }
在getView方法中每次都要把布局加载一遍,当ListView快速滚动的时候,会造成性能的瓶颈。方法中的convertView参数用于将之前加载的布局进行缓存,修改代码如下:
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Fruit fruit = getItem(position);
View view ;
if (convertView == null){
view = LayoutInflater.from(getContext()).inflate(resource, parent, false);
}else {
view = convertView;
}
AppCompatImageView fruitImage = view.findViewById(R.id.fruit_image);
AppCompatTextView fruitName = view.findViewById(R.id.fruit_name);
fruitImage.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());
return view;
}
现在虽然不会重复加载布局,但是还是会调用View的FindViewById()方法来获取一次控件的实例。可以借助ViewHolder 进行优化
@NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { Fruit fruit = getItem(position); View view ; ViewHolder viewHolder; if (convertView == null){ view = LayoutInflater.from(getContext()).inflate(resource, parent, false); viewHolder = new ViewHolder(); viewHolder.fruitImage = view.findViewById(R.id.fruit_image); viewHolder.fruitName = view.findViewById(R.id.fruit_name); view.setTag(viewHolder); }else { view = convertView; viewHolder = (ViewHolder) view.getTag(); } viewHolder.fruitImage.setImageResource(fruit.getImageId()); viewHolder.fruitName.setText(fruit.getName()); return view; }
class ViewHolder{
AppCompatImageView fruitImage;
AppCompatTextView fruitName;
}
内部类ViewHolder用于对控件的实例进行缓存,当convertView为null时,创建ViewHolder对象,并将控件的实例都存放在ViewHolder中,调用View 的setTag()方法将ViewHolder对象存储在View中,当convertView不为null时,通过View的getTag()方法取出ViewHolder,这样所有控件的实例都存储在了ViewHolder中,就没必要每次都通过findViewById()方法来获取控件实例了。