布局与控件 第10节 ListView的Adapter

更新时间 修改意见
2016-08-02 陈敏

第10节 ListView的Adapter

安卓系统为ListView设计了多种Adapter作为它的搭档。每种Adapter不仅为ListView提供数据内容,也会告诉ListView如何展示这些数据-规定好列表项的长相。

这些Adapter都是从Adapter类继承而来的,它们的关系如下:

这里我们选择性的介绍常见的2种AdapterArrayAdapterSimpleAdapter

10.1 ArrayAdapter

ArrayAdapter是最简单的Adapter,我们在前面已经使用过它,

在创建ArrayAdapter的时候,

  1. 要声明这个Adapter要接受什么类型的数据,

  2. 指定布局文件的layout id

    这个布局就是一个TextView,只不过被指定了android:id@android:id/text1

    注意这里在给控件指定ID的时候用的是`@id/text1,而没有用+。这表明,这个ID值是已经存在的,而不需要编译器再单独分配。

    这样ArrayAdapter会自动寻找这个布局文件中ID名字为text1的控件,并认为它就是可以用来显示数据的TextView

    如果不想用系统给TextView指定的ID,也可以给自己定义的布局的TextView取个名字,例如show_content_textview

    然后向ArrayAdapter再传入一个ID,告诉它将要显示的文字,放到这个ID所指示的控件上,

  3. 传入要显示的数据内容,这个数据内容可以以数组的方式传入,也可以以List的方式放入,

10.2 SimpleAdapter

看得出ArrayAdapter是相当的简单,只能在单一的TextView上显示一条数据。如果有好几条不同类型的数据要显示到同一列表项的不同部位,那就不好办了。SimpleAdapter正好能帮我们解决这样的问题。虽然它叫Simple,不过不是说功能simple,而是使用很simple。

它的设计思路是,

  1. 每一条列表项上哪些控件希望显示数据都要告诉SimpleAdaperSimpleAdaper只要知道这些控件的ID就可以了。所以在创建的时候,需要传入这些控件的ID值(以数组的形式);

  2. 每一项待显示的数据,要和列表上的控件一一对应。这就需要一个翻译系统,给每个位置的数据取个名字,将待显示数据挨个放入键值对的列表中(map);并将每个位置的数据名字和控件ID值对应起来;

  3. SimpleAdapter在绑定数据到界面上的时候,就根据对应关系,一个一个把它们放上去。

例如,

  1. 准备要显示的数据,让每个数据项,和一个特定的名字(title pic content)对应上,

  2. 将特定的名称做成数组,和显示区域的ID一一对应上,例如,

    title <-> R.id.title_id
    pic <-> R.id.pic_id
    content <-> R.id.content_id

  3. 创建SimpleAdapter

10.3 自定义Adapter

虽然Android SDK为我们提供了好几种现成的Adapter使用,但有时它们也并不能完全符合我们的要求,要么用起来还是麻烦,要么大材小用。另外,为了把ListView介绍的全面一些,我们准备自定义一个Adapter。

10.3.1 定义数据项的布局

为了让列表的数据项按照我们设计的模样显示,我们需要为它设计一个布局,用展示的视频列表为例,加以说明。

数据项的布局定义在res\layout\video_item.xml文件中,

  1. 数据项显示在水平布局的LinearLayout中;
  2. 视频缩略图用ImageView控件显示,给它的android:scaleType属性设置center,让缩略图居中放置,背景设置成应用主题的色调colorPrimary
  3. 其他视频信息包含标题和创建时间,将它们竖直排列放在一个LinearLayout中,占用高度按照2:1分配,前者使用主题中较大的字体?android:attr/textAppearanceMedium,后者使用主题中较小的字体?android:attr/textAppearanceSmall
  4. 至于各个组件之间的间隔,根据自己的视觉偏好调整就好了,用android:paddingandroid:layout_margin设置;

10.3.2 定义数据项内容

为每个视频信息,定义一个数据结构VideoItem

10.3.3 定义Adapter

所有Adapter都是继承自BaseAdapter的,我们自定义的Adapter也继承自它。

  1. 继承BaseAdapter,准备实现必须实现的基类函数;

  2. 创建构造函数,在构造函数中,保存好布局ID,以便以后使用,通过Context获取Inflater,为以后数据项布局的创建做准备;保存要展示的数据项们;

  3. 实现getCount()函数,返回当前数据项的个数,

  4. 实现getItem()函数,根据传入的索引号,返回对应的数据项,

  5. 实现getItemId()函数,根据传入的索引号,返回对应项的id值,

  6. getView()函数中,创建数据项的布局,并为他们赋值,最后将这个布局返回给ListView,让它显示,

    这里的convertView就是数据项所代表的那个布局,当ListView刚创建,还没有产生任何数据项的时候,它就是为null的,此时我们就需要创建一个布局,并通过getView()将这个布局返回给ListView

    假如ListView上的数据项布局已经足够了,那么这里传入的convertView就不会再是“null”,而是之前的某个数据项布局,我们就不必为此重新创建了,只需要更新上面的内容就好。这样提高了界面刷新的效率。

    当然,这里还能通过其他方法减少使用findViewById(),进一步提高效率,不过目前就不改进了,先把功能实现完成。


综合以上内容,最后的代码就是,

10.3.4 使用自定义Adapter

  1. 在Video List的Activity创建之时,我们在onCreate()中创建并设置VideoAdapter

  2. 当列表中的数据有变化时,在主线程中更新数据列表,并使用notifyDataSetChanged()刷新,

10.3.5 改进提高效率

在前面实现自定义Adapter的getView()函数中,没有每次都创建一个convertView,而是复用已有的布局,这样就节省重新创建的资源。不过每次都使用findViewById()也会花掉不少的开销。

为此,我们可以引入一个数据结构,将这些控件保存下来,在使用的时候直接获取,不需要进行耗时的findViewById()操作了。

  1. 创建一个数据类,准备存放控件,

  2. 创建布局的时候,通过创建Holder将控件保存起来,

  3. 获取Holder,直接使用,提高效率,


/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/