✏️
Android应用开发
  • 简介
  • 目录
  • 第一章 熟悉Android Studio开发环境
    • 第一个项目——Hello World!
    • 第二个项目——计数器
    • 第三个项目——新闻阅读器
  • 第二章 活动、组件及布局
    • 第四个项目——消息发送
    • 第五个项目——计数器2
    • 第六个项目——登陆界面
    • 第七个项目——新闻列表
  • 第三章 数据持久化
    • 第八个项目——登陆界面2
    • 第九个项目——新闻列表2
  • 第四章 内容提供器与数据共享
    • 第十个项目——音乐播放器1
  • 第五章 多媒体与服务
    • 第十一个项目——音乐播放器2
    • 第十二个项目——音乐播放器3
  • 第六章 绑定服务与自定义广播
    • 第十三个项目——音乐播放器4
  • 第七章 网络与多线程
    • 第十四个项目——新闻列表3
  • 附录 扩展项目
    • 第十五个项目——使用ViewHolder提升ListView显示性能
    • 第十六个项目——使用SwipeRefreshLayout实现下拉刷新
    • 第十七个项目——使用接口回调实现删除ListView列表中的Item数据
    • 第十八个项目——使用RecyclerView显示列表数据
    • 第十九个项目——使用Fragment组织UI页面
    • 第二十个项目——使用CursorAdapter进行数据绑定及渲染
    • 第二十一个项目——使用Loader实现异步数据加载操作
    • 第二十二个项目——使用TimerTask及Handler实现秒表计时器
    • 第二十三个项目——使用AsyncTask进行网络异步请求
Powered by GitBook
On this page
  • 实验目的
  • 实验要求
  • 实验内容
  • 步骤一,打开第七个项目
  • 步骤二,定义ViewHolder类
  • 步骤三,更改NewsAdapter.getView()方法
  • 步骤四,编译并运行项目
  • 实验小结

Was this helpful?

  1. 附录 扩展项目

第十五个项目——使用ViewHolder提升ListView显示性能

Previous附录 扩展项目Next第十六个项目——使用SwipeRefreshLayout实现下拉刷新

Last updated 4 years ago

Was this helpful?

实验目的

  • 掌握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;
    }
}

步骤一,打开第七个项目

步骤二,定义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()的方式进行读取即可。具体代码如下所示。

View.setTag(Object obj)方法的参数为Object类型,通过该方法可以把任意类型的数据跟当前的View对象进行绑定,后续还可以见到更多这类使用方式。

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控件运行性能;

  • 使用ViewHolder存储ListView的Item布局控件;

  • 使用View.setTag()、View.setTag()将数据绑定至控件;

打开,并打开文件NewsAdapter.java。

例如删除ListView控件中某一个Item时,首先将当前Item对应数据的Id与表示删除图标的ImageView控件进行绑定(通过setTag()方法),再实现该ImageView控件的OnClickListener事件处理器中通过getTag()方法取出Id,并执行相应的删除操作。 具体详见。

编译并运行项目,其执行效果与相同,你可以为ListView的数据源添加更多的数据对比一下其性能是否有提升。

第七个项目
第七个项目
第十七个项目
第七个项目