Android ListView
一、 了解ListView
在Android所有常用的原生控件中,用法最复杂的应该就是LsitView了,它专门用于处理那种内容元素很多,手机屏幕无法展示出所有内容的情况。ListView可以使用列表的形式来展示内容,超出屏幕的不分的内容只需要通过手指滑动就可以移动到屏幕内。我相信大家应该都体验过,即使在ListView中加载非常非常多的数据,比如达到成百上千条甚至更多,ListView都不会发生OOM或者崩溃,而且随着我们手指滑动来浏览更多数据时,程序所占用的内存竟然都不会跟着增长。那么ListView是怎么实现这么神奇的功能的呢?
二、 OOM(out of memory —— 内存泄漏)
在一个程序中,已经不需要使用某个对象的时候,但是因为仍然有引用指向它,垃圾回收器就无法回收它。像这样的对象占用的内存无法被回收时,就容易出现内存泄漏。而内存泄漏导致的后果就是系统Kill掉这个应用程序,当然如果系统是system_process等系统的时候就会引起系统重启。(http://blog.csdn.net/boyupeng/article/details/47726765)
而使ListView能够拥有加载大数据的同时不出现OOM和奔溃的神奇功能的原因是 *RecycleBin机制* 。(http://blog.csdn.net/iispring/article/details/50967445)
三、 ListView的继承结构图
可以看到,ListView的继承结构还是比较复杂的,它是直接继承AbsListView的,而AbsListView有两个子实现类,一个是ListView,另一个就是GridView,因此我们从这一点就可以猜出两者在工作原理和实现上都有很多的共同点。然后AbsListView又继承自AdapterView,AdapterView继承自ViewGroup。
四、 Adapter
Adapter相信大家都不会陌生,我们平时使用ListView的时候一定都会用到它。那么话说回来大家有没有仔细想过,为什么需要Adapter这个东西呢?总感觉正因为有了Adapter,ListView的使用变得要比其它控件复杂得多。那么这里我们就先来学习一下Adapter到底起到了什么样的一个作用。
其实说到底,控件就是为了交互和展示数据用的,只不过ListView更加特殊,它是为了展示很多很多数据用的,但是ListView只承担交互和展示工作而已,至于这些数据来自哪里,ListView是不关心的。因此,最基本的ListView工作模式就是要有一个ListView控件和一个数据源。
不过如果真的让ListView和数据源直接打交道的话,那ListView所要做的适配工作就非常繁杂了。因为数据源这个概念太模糊了,我们只知道它包含了很多数据而已,至于这个数据源到底是什么样类型,并没有严格的定义,有可能是数组,也有可能是集合,甚至有可能是数据库表中查询出来的游标。所以说如果ListView真的去为每一种数据源都进行适配操作的话,一是扩展性会比较差,内置了几种适配就只有几种适配,不能动态进行添加。二是超出了它本身应该负责的工作范围,不再是仅仅承担交互和展示工作就可以了,这样ListView就会变得比较臃肿。
那么显然Android开发团队是不会允许这种事情发生的,于是就有了Adapter这样一个机制的出现。顾名思义,Adapter是适配器的意思,它在ListView和数据源之间起到了一个桥梁的作用,ListView并不会直接和数据源打交道,而是会借助Adapter这个桥梁来去访问真正的数据源,与之前不同的是,Adapter的接口都是统一的,因此ListView不用再去担心任何适配方面的问题。而Adapter又是一个接口(interface),它可以去实现各种各样的子类,每个子类都能通过自己的逻辑来去完成特定的功能,以及与特定数据源的适配操作,比如说ArrayAdapter可以用于数组和List类型的数据源适配,SimpleCursorAdapter可以用于游标类型的数据源适配,这样就非常巧妙地把数据源适配困难的问题解决掉了,并且还拥有相当不错的扩展性。简单的原理示意图如下所示:
五、例子
我们要实现一个ListView控件的数据显示,那么首先就要布局一个ListView控件。
在上图中就是我们在布局文件中添加的一个ListView控件了,并且为它添加了一些属性:id、divider、choiceMode、listSelector。它们分别是设定ListView的id、边距效果、选择模式和选定样式。
接下来是它的事件和使用Adapter为它绑定数据: