之所以说 ListView 这个控件很难用,就是因为它有很多的细节可以优化,其中运行效率 就是很重要的一点。目前我们 ListView 的运行效率是很低的,因为在 FruitAdapter 的 getView() 方法中每次都将布局重新加载了一遍,当 ListView 快速滚动的时候这就会成为性能的瓶颈。

仔细观察,getView()方法中还有一个 convertView 参数,这个参数用于将之前加载好的 布局进行缓存,以便之后可以进行重用。修改 FruitAdapter 中的代码,如下所示:

public class FruitAdapter extends ArrayAdapter<Fruit> {

……

@Override

public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position);

View view;

if (convertView == null) {

view = LayoutInflater.from(getContext()).inflate(resourceId, null);

} else {

view = convertView;

}

ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image); TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
fruitImage.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());

return view;

}

}

可以看到,现在我们在 getView()方法中进行了判断,如果 convertView 为空,则使用 LayoutInflater 去加载布局,如果不为空则直接对 convertView 进行重用。这样就大大提高了
ListView 的运行效率,在快速滚动的时候也可以表现出更好的性能。

不过,目前我们的这份代码还是可以继续优化的,虽然现在已经不会再重复去加载布局,
但是每次在 getView()方法中还是会调用 View 的 findViewById()方法来获取一次控件的实例。
我们可以借助一个 ViewHolder 来对这部分性能进行优化,修改 FruitAdapter 中的代码,如下
所示:

public class FruitAdapter extends ArrayAdapter<Fruit> {

……

@Override

public View getView(int position, View convertView, ViewGroup parent) { Fruit
fruit = getItem(position);

View view;

ViewHolder viewHolder;

if (convertView == null) {

view = LayoutInflater.from(getContext()).inflate(resourceId, null);

viewHolder = new ViewHolder();

viewHolder.fruitImage = (ImageView) view.findViewById

(R.id.fruit_image);

viewHolder.fruitName = (TextView) view.findViewById

(R.id.fruit_name);

view.setTag(viewHolder); // ViewHolder存储在View

} else {

view = convertView;

viewHolder = (ViewHolder) view.getTag();
//
重新获取ViewHolder

}
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());

return view;

}

class ViewHolder { ImageView fruitImage;
TextView fruitName;

}

}

我们新增了一个内部类 ViewHolder,用于对控件的实例进行缓存。当 convertView 为空 的时候,创建一个 ViewHolder 对象,并将控件的实例都存放在 ViewHolder 里,然后调用 View 的 setTag()方法,将 ViewHolder 对象存储在 View 中。当 convertView 不为空的时候则调用 View 的 getTag()方法,把 ViewHolder 重新取出。这样所有控件的实例都缓存在了 ViewHolder
里,就没有必要每次都通过 findViewById()方法来获取控件实例了。

通过这两步的优化之后,我们 ListView 的运行效率就已经非常不错了。

3.5.4    ListView 的点击事件

话说回来,ListView 的滚动毕竟只是满足了我们视觉上的效果,可是如果 ListView 中的 子项不能点击的话,这个控件就没有什么实际的用途了。因此,本小节中我们就来学习一下 ListView 如何才能响应用户的点击事件。

修改 MainActivity 中的代码,如下所示:

public class MainActivity extends Activity {

private List<Fruit> fruitList = new
ArrayList<Fruit>();

@Override

protected void
onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); initFruits();

FruitAdapter adapter = new
FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);

ListView listView = (ListView)
findViewById(R.id.list_view); listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener() {

@Override

public void
onItemClick(AdapterView<?> parent, View view, int position, long id) {

Fruit fruit = fruitList.get(position);
Toast.makeText(MainActivity.this, fruit.getName(),

Toast.LENGTH_SHORT).show();

}

});

}

……

}

可以看到,我们使用了 setOnItemClickListener()方法来为 ListView 注册了一个监听器,
当用户点击了 ListView 中的任何一个子项时就会回调 onItemClick()方法,在这个方法中可以
通过
position 参数判断出用户点击的是哪一个子项,然后获取到相应的水果,并通过 Toast 将水果的名字显示出来。

重新运行程序,并点击一下西瓜,效果如图 3.31 所示。

图   3.31

android:提升 ListView 的运行效率的更多相关文章

  1. Android笔记——提升ListView的运行效率

    之所以说 ListView 这个控件很难用,就是因为它有很多的细节可以优化,其中运行效率就是很重要的一点.目前我们ListView 的运行效率是很低的,因为在 FruitAdapter 的getVie ...

  2. 初识ListView - 定制ListView - 提升ListView运行效率

    ListView绝对可以称得上是 Android 中最常用的控件之一,几乎所有的应用程序都会用到它.由于手机屏幕空间都比较有限,能够一次性在屏幕上显示的内容并不多,当我们的程序中有大量的数据需要展示的 ...

  3. Android中ListView实现图文并列并且自定义分割线(完善仿微信APP)

    昨天的(今天凌晨)的博文<Android中Fragment和ViewPager那点事儿>中,我们通过使用Fragment和ViewPager模仿实现了微信的布局框架.今天我们来通过使用Li ...

  4. Android中ListView的用法

    使用方法1 显示简单的文本 在layout文件中像加入普通控件一样在layout文件中引入ListView <ListView android:id="@+id/list_view&q ...

  5. java攻城狮之路(Android篇)--ListView与ContentProvider

    一.ListView 1.三种Adapter构建ListView ListView添加条目的时候, 可以使用setAdapter(ListAdapter)方法, 常用的ListAdapter有三种 B ...

  6. 43.Android之ListView中BaseAdapter学习

    实际开发中个人觉得用的比较多是BaseAdapter,尽管使用起来比其他适配器有些麻烦,但是使用它却能实现很多自己喜欢的列表布局,比如ListView.GridView.Gallery.Spinner ...

  7. Android杂谈--ListView之BaseAdapter的使用

    话说开发用了各种Adapter之后感觉用的最舒服的还是BaseAdapter,尽管使用起来比其他适配器有些麻烦,但是使用它却能实现很多自己喜欢的列表布局,比如ListView.GridView.Gal ...

  8. Android在ListView显示图片(重复混乱闪烁问题)

    Android在ListView显示图片(重复混乱闪烁问题) 1.原因分析 ListView item缓存机制: 为了使得性能更优,ListView会缓存行item(某行相应的View). ListV ...

  9. Android在ListView滑动数据混乱

    我相信做过Android应用程序开发或多或少都遇到了这个问题.或者是在ListView数据损坏幻灯片事件.要么GridView数据损坏幻灯片事件. 让我们来看看一个网友写的文章,个人感觉还不错的文章: ...

随机推荐

  1. PYTHON-绑定方法 反射 内置函数

    '''绑定方法类中定义函数分为了两大类: 1. 绑定方法 特殊之处: 绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数自动传入 如何用: 绑定给对象的方法: 在类中定义函数没有被任何装饰器修饰 ...

  2. ORACLE与SQLSERVER数据转换

    前言: 将SQLServer数据库中的表和数据全量导入到Oracle数据库,通过Microsoft SqlServer Management Studio工具,直接导入到oracle数据库,免去了生成 ...

  3. mysql的undo log和redo log

    在数据库系统中,既有存放数据的文件,也有存放日志的文件.日志在内存中也是有缓存Log buffer,也有磁盘文件log file,本文主要描述存放日志的文件.     MySQL中的日志文件,有这么两 ...

  4. web----WSGI

    概念: WSGI协议其实是定义了一种server与application解耦的规范 WSGI规范简单理解:一方面给Server提供接口,凡是以这种接口的web服务器,都是遵循WSGI规范的 另一方面给 ...

  5. Nginx部署多个网站

    为节省资源,通常一个服务器会运行多个网站,通常一个服务一个IP,多个域名共用一个IP,多个域名共用一个端口(通常是80端口). 这时候需要一台服务器部署多个网站,多个网站共用一个IP,共用一个80端口 ...

  6. 【C++ Primer | 15】虚继承

    虚基类 一.虚基类介绍 多继承时很容易产生命名冲突,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如非常经典的菱形继承层次.如下图所示: 类A派生出类B和 ...

  7. 学习C程序设计(一)第一节总览

    1.程序设计面向的问题 一切可计算问题都可以用程序的方法解决.ps:这样程序与计算有关了 1.1程序设计的五个步骤: a.确定问题可以计算:(问题是可计算) b.建立问题的数学模型:(不懂) c.设计 ...

  8. C# 收发和处理自定义的WINDOWS消息

    C# 发送.接收和处理自定义的WINDOWS消息 转载地址:http://blog.chinaunix.net/uid-24427209-id-2608350.html 为了程序启动后自动执行主函数, ...

  9. Go 语言 IDE 之 VSCode 配置使用

    Gogland 是 JetBrains 公司推出的 Go 语言集成开发环境.Gogland 同样基于 IntelliJ 平台开发,支持 JetBrains 的插件体系.官方:https://www.j ...

  10. Compoer的应用

    composer总结 composer常用命令 composer list 列出所有可用的命令composer init 初始化composer.json文件(就不劳我们自己费力创建啦),会要求输入一 ...