Android学习笔记 -- BaseAdapter

October . 15 . 2018
  • 什么是数据适配

下图展示了数据源、适配器、ListView等数据展示控件之间的关系。我们知道,数据源是各种各样的,而ListView所展示数据的格式则是有一定的要求的。数据适配器正是建立了数据源与ListView之间的适配关系,将数据源转换为ListView能够显示的数据格式,从而将数据的来源与数据的显示进行解耦,降低程序的耦合性。这也体现了Android的适配器模式的使用。对于ListView、GridView等数据展示控件有多种数据适配器,本文讲解最通用的数据适配器——BaseAdapter。adapter.jpg

  • ListView的显示与缓存机制

我们知道,ListView、GridView等控件可以展示大量的数据信息。假如下图中的ListView可以展示100条信息,但是屏幕的尺寸是有限的,一屏幕只能显示下图中的7条。当向上滑动ListView的时候,item1被滑出了屏幕区域,那么系统就会将item1回收到Recycler中,即View缓冲池中,而将要显示的item8则会从缓存池中取出布局文件,并重新设置好item8需要显示的数据,并放入需要显示的位置。这就是ListView的缓冲机制,总结起来就是一句话:需要时才显示,显示完就被会收到缓存。ListView,GridView等数据显示控件通过这种缓存机制可以极大的节省系统资源。

adapter2.png

  • BaseAdapter

使用BaseAdapter比较简单,主要是通过继承此类来实现BaseAdapter的四个方法:

public int getCount(): 适配器中数据集的数据个数;

public Object getItem(int position): 获取数据集中与索引对应的数据项;

public long getItemId(int position): 获取指定行对应的ID;

public View getView(int position,View convertView,ViewGroup parent): 获取没一行Item的显示内容。

下面通过一个简单示例演示如何使用BaseAdapter。

1. 创建布局文件

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent">

    <ListView

        android:id="@+id/id_listView"

        android:layout_width="match_parent"

        android:layout_height="match_parent"/>

</LinearLayout>

2. 创建 ListView 子布局

list_item.xml
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent">

    <ImageView

        android:id="@+id/image_view"

        android:layout_width="50dp"

        android:layout_height="60dp"

        android:layout_margin="6dp"

        android:src="@drawable/apple"/>

    <TextView

        android:id="@+id/name_text_view"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_toRightOf="@id/image_view"

        android:text="apple"

        android:textSize="24sp"

        android:layout_margin="5dp"/>

    <TextView

        android:id="@+id/content_text_view"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_toEndOf="@id/image_view"

        android:layout_below="@id/name_text_view"

        android:textSize="15sp"

        android:text="我是一个苹果"

        android:layout_margin="5dp"/>

</RelativeLayout>

3. 创建数据源

Fruit.java
package example.baseadaptertest;

/**
 * Created by Administrator on 2018/10/15.
 */

public class Fruit {

    public int imageId;     // 图片资源
    public String name;     // 水果名
    public String description;  // 水果简介

    Fruit(int imageId, String name, String description)
    {
        this.imageId = imageId;
        this.name = name;
        this.description = description;
    }
}

通过此Fruit类,将要显示的数据与ListView的布局内容一一对应,每个Fruit对象对应ListView的一条数据。

MainActivity.java
package example.baseadaptertest;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    ListView listView;

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

        listView = (ListView) findViewById(R.id.id_listView);
        List<Fruit> datas = new ArrayList<>();

        int[] drawables = {R.drawable.apple, R.drawable.strawberry};

        for (int i = 0; i< 20 ; i++)
        {
            if (i%2 == 0)
                datas.add(new Fruit(drawables[0], "苹果", "又大又红又甜"));
            else
                datas.add(new Fruit(drawables[1], "草莓", "又黄又小又酸"));
        }

        listView.setAdapter(new FruitAdapter(this, datas));
    }
}

4. 创建BaseAdapter (注意看代码注释)

FruitAdapter.java
package example.baseadaptertest;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

/**
 * Created by Administrator on 2018/10/15.
 */

public class FruitAdapter extends BaseAdapter {

    private List<Fruit> datas; // 数据源
    private LayoutInflater inflater;  // 布局装载对象

    FruitAdapter(Context context, List<Fruit> datas)
    {
        this.datas = datas;
        this.inflater = LayoutInflater.from(context);
    }

    // 需要显示的数据总量
    @Override
    public int getCount() {
        return datas.size();
    }

    // 指定索引对应的数据项
    @Override
    public Object getItem(int position) {
        return datas.get(position);
    }

    // 指定索引对应的数据项ID
    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        // 没有缓存
        if (convertView == null) {
            viewHolder = new ViewHolder();

            // 只需要将XML转化为View,并不涉及到具体的布局,所以第二个参数通常设置为null
            convertView = inflater.inflate(R.layout.list_item, null);

            // 对 viewHolder 的值进行赋值
            viewHolder.imageView = convertView.findViewById(R.id.image_view);
            viewHolder.name = convertView.findViewById(R.id.name_text_view);
            viewHolder.description = convertView.findViewById(R.id.content_text_view);

            // 通过 setTag 将 convertView 与 viewHolder 关联
                convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // 获取对应索引的Fruit对象
        Fruit fruit = datas.get(position);

        viewHolder.name.setText(fruit.name);
        viewHolder.description.setText(fruit.description);
        viewHolder.imageView.setImageResource(fruit.imageId);

        return convertView;
    }

    // 用于缓存控件, 三个属性分别对应item布局的三个控件
    class ViewHolder{
        public ImageView imageView;
        public TextView name;
        public TextView description;
    }
}

5. 总结一下整体步骤

  1. 创建数据适配器
  2. 实现相应接口方法
  3. 创建数据源
  4. 利用convertView优化布局加载速度

原文地址: 链接在此