第十五个项目——使用ViewHolder提升ListView显示性能
实验目的
掌握ListView中Item布局加载机制;
掌握View.setTag()及View.getTag()读取数据的方式;
实验要求
自定义ViewHolder保存Item布局控件实例
修改NewsAdapter.getView()方法提升Item加载效率;
实验内容
在第七个项目中,使用了ListView用于显示新闻列表。为了实现ListView中的Item加载自定义布局,项目中实现了名为NewsAdapter的适配器类,在该类中覆盖了getView()方法。当用户上下滑动ListView时,该方法被调用; 该方法中需要返回当前postion对应的Item布局,原代码中在getView()方法中每次都通过LayoutInflater加载list_item.xml布局资源,并实例化相应的TextView、ImageView控件。
假设ListView中的数据源包含成千上万条数据,最极端的情况下,用户滑动ListView到底部,那么App将有上万个TextView、ImageView控件的实例,但是ListView能在屏幕上显示的数据远远小于数据源所包含的数据量,这样的做法无疑会降低App的运行效率。有什么办法可以提升ListView加载显示数据的效率?如果当ListView中某一Item滑出屏幕时,新滑入的Item能复用其实例化的布局就可以避免刚才所说的问题。
实际上ListView控件提供了缓存机制,可有效提高Item布局加载效率低下的问题。getView()方法的第二个参数(View convertView)如果不为null则保存了被缓存的Item布局实例。
public class NewsAdapter extends ArrayAdapter<News> {
...
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
News news = getItem(position);
View view ;
view = LayoutInflater.from(getContext())
.inflate(resourceId, parent, false);
TextView tvTitle = view.findViewById(R.id.tv_title);
TextView tvAuthor = view.findViewById(R.id.tv_subtitle);
ImageView ivImage = view.findViewById(R.id.iv_image);
tvTitle.setText(news.getTitle());
tvAuthor.setText(news.getAuthor());
ivImage.setImageResource(news.getImageId());
return view;
}
}
步骤一,打开第七个项目
打开第七个项目,并打开文件NewsAdapter.java。
步骤二,定义ViewHolder类
在NewsAdapter中定义名为ViewHolder的内部类(inner class),ViewHolder中包含了list_item.xml布局中三个控件的定义,其主要作用为保存每一个Item布局中控件的实例。
public class NewsAdapter extends ArrayAdapter<News> {
...
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
...
}
class ViewHolder {
TextView tvTitle;
TextView tvAuthor;
ImageView ivImage;
}
}
步骤三,更改NewsAdapter.getView()方法
在NewsApdater适配器类的getView()方法中,通过判断convertView是否为空,可判断ListView是否缓存了Item的布局,如果已缓存则可直接使用,否则需要通过Layoutinflater进行加载。
通过LayoutInflater进行加载的Item布局中的控件实例,通过实例化ViewHolder类对象进行存储, 而通过view.setTag(Object viewHolder)将ViewHolder类对象存储于view对象中,ViewHolder对象可通过view.getTag()的方式进行读取即可。具体代码如下所示。
public class NewsAdapter extends ArrayAdapter<News> {
...
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
News news = getItem(position);
View view ;
ViewHolder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(getContext())
.inflate(resourceId, parent, false);
viewHolder = new ViewHolder();
viewHolder.tvTitle = view.findViewById(R.id.tv_title);
viewHolder.tvAuthor = view.findViewById(R.id.tv_subtitle);
viewHolder.ivImage = view.findViewById(R.id.iv_image);
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.tvTitle.setText(news.getTitle());
viewHolder.tvAuthor.setText(news.getAuthor());
viewHolder.ivImage.setImageResource(news.getImageId());
return view;
}
class ViewHolder \{
TextView tvTitle;
TextView tvAuthor;
ImageView ivImage;
}
}
步骤四,编译并运行项目
编译并运行项目,其执行效果与第七个项目相同,你可以为ListView的数据源添加更多的数据对比一下其性能是否有提升。
实验小结
通过本次实验,你应该掌握了如下知识内容:
了解如何提升ListView控件运行性能;
使用ViewHolder存储ListView的Item布局控件;
使用View.setTag()、View.setTag()将数据绑定至控件;
Last updated
Was this helpful?