Android Adapter 适配器

Android Adapter ( 适配器 ) 是用来帮助填充数据的中间桥梁, 简单点说就是:将各种数据以合适的形式显示到 view 上,提供给用户看

我们前面学的那些 UI 控件都是很简单的,要么用户获取用户输入,要么是简单的设置,但我们往往看到很多很复杂的列表,比如为微信的这个页面

要显示这么复杂的数据,就要用到 Adapter

MVC 模式

为了更好的理解 Adapter 的作用,我们先来了解下 MVC 模式

MVC 是什么呢?

举个例子,大多数大型餐饮店,有切菜的,有厨师,也有点菜员

点菜员负责记录客户要什么菜,然后把菜名告诉厨师,厨师则负责做菜,切菜的则根据厨师要做的菜准备各项材料

点菜的只要跟厨师交流就可以了,而切菜的只要准备好材料,也不用和点菜员交流,这就是分工模式,也是 MVC 模式的精髓

MVC 模式就是 模型(M)-视图(V)-控制器(C) ,其中控制器是连接另外两者的桥梁,就像厨师

  • Model :通常可以理解为数据,负责执行程序的核心运算与判断逻辑,通过 view 获得用户 输入的数据,然后根据从数据库查询相关的信息,最后进行运算和判断,再将得到的结果交给view来显示

  • view : 用户的操作接口,说白了就是 GUI,应该使用哪种接口组件,组件间的排列位置与顺序都需要设计

  • Controller :控制器,作为 model 与 view 之间的枢纽,负责控制程序的执行流程以及对象之间的一个互动

Adapter 就是中间的这个 Controller 部分

Model(数据)  ---> Controller(以什么方式显示到)---> View(用户界面)

Adapter

我们先来看看 Adapter 的继承关系图

说明
BaseAdapter 抽象类,用得最多的 Adapter
ArrayAdapter 支持泛型操作,最简单的 Adapter,只能展现一行文字
SimpleAdapter 同样具有良好扩展性的 Adapter,可以自定义多种效果
SimpleCursorAdapter 用于显示简单文本类型的 ListView,不推荐使用

范例

理论的东西,说多了头疼,我们程序员的宗旨就是 talk nothing show me the code

我们先来演示下 ArrayAdpter 的简单使用

  1. 创建一个 空的 Android 项目 cn.twle.android.ArrayAdapter

  2. 修改 activity_main.xml 添加一个 ListView

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp" 
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    

    我们后面会将 ListView,这里先用起来再说

  3. 修改 MainActivity.java

    package cn.twle.android.arrayadapter;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    import android.widget.ArrayAdapter;
    
    import android.widget.ListView;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //要显示的数据
            String[] strs = {"Android","iOS","Java","Python","Ruby"};
    
            // 创建 ArrayAdapter
            // 构造函数的参数,第一个是上下文对象,第二个是列表项的模板,第三个就是数组
            ArrayAdapter<String> adapter = new ArrayAdapter<String>
                    (this,android.R.layout.simple_expandable_list_item_1,strs);
    
            // 获取 ListView 对象
            // 通过调用 setAdapter() 方法为 ListView 设置 Adapter 设置适配器
    
            ListView listview = (ListView) findViewById(R.id.listview);
            listview.setAdapter(adapter);
        }
    }
    

Adapter 的数据除了可以在 Java 代码中通过数组定义外,还可以使用 XML 文件来定义

  1. 创建一个 空的 Android 项目 cn.twle.android.ArrayAdapter

  2. res\values 新建一个数组资源的 XML 文件: arrays.xml

    <?xml version="1.0" encoding="utf-8"?>  
    <resources>  
        <string-array name="it_languages">  
            <item>Android</item>  
            <item>iOS</item>  
            <item>Java</item>
            <item>Python</item>
            <item>Perl</item>
        </string-array>      
    </resources>
    
  3. 然后修改 activity_main.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp" 
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:entries="@arrays/it_languages" />
    </LinearLayout>
    

运行后效果是一样的,我们就不贴图了

如果你复用上面的 demo,则需要将 MainActivity.java 中修改为

    package cn.twle.android.arrayadapter;

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

    public class MainActivity extends AppCompatActivity {

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

当然我们也可以在 Java 代码中这样写

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
        R.array.myarray,android.R.layout.simple_list_item_multiple_choice );

ArrayAdapter 泛型

我们前面介绍 ArrayAdapter 时有提到它支持泛型数据

所以我们可以把一个集合 ( List ) 直接作为第三个参数

List<String> data = new ArrayList<String>();

data.add("C++");
data.add("Python")

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1,data);

ArrayAdapter 构造函数的第二个参数

差点忘记介绍那个老长的参数

android.R.layout.simple_expandable_list_item_1

这其实是我们要给 ListView 设置的模板,有好几种

  1. simple_list_item_1

    单独一行的文本框

  2. simple_list_item_2

    两个文本框组成

  3. simple_list_item_checked

    每项都是由一个已选中的列表项

  4. simple_list_item_multiple_choice

    都带有一个复选框

  5. simple_list_item_single_choice

    都带有一个单选钮

SimpleAdapter 适配器

SimpleAdapter 适配器是最简单的 Adapter,虽然简单,但功能一点也没垫底

废话不说,直接上效果图

  1. 创建一个 空的 Android 项目 cn.twle.android.SimpleAdapter

  2. 下载 /static/i/android/it_language_icon.zip 解压并把所有的图片拖到 res/drawable 目录

  3. 修改 activity_main.xml 添加一个 ListView

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp" 
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    
  4. 最重要的来了,我们要定义列表中每一行的布局,在 res/layout 目录下新建一个文件 list_item.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"
        android:orientation="horizontal">
    
        <!-- 定义一个用于显示头像的 ImageView -->
        <ImageView
            android:id="@+id/icon"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:baselineAlignBottom="true"
            android:paddingLeft="8dp" />
    
        <!-- 定义一个竖直方向的 LinearLayout,把 语言 与 简介 的文本框设置出来 -->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
    
            <TextView
                android:id="@+id/name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingLeft="8dp"
                android:textColor="#1D1D1C"
                android:textSize="20sp" />
    
            <TextView
                android:id="@+id/desc"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingLeft="8px"
                android:textColor="#B4B4B9"
                android:textSize="14sp" />
    
        </LinearLayout>
    </LinearLayout>
    

    布局很简单,复杂一点的都用注释说清楚了

  5. 修改 MainActivity.java

    package cn.twle.android.simpleadapter;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    import android.widget.SimpleAdapter;
    
    import android.widget.ListView;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class MainActivity extends AppCompatActivity {
    
        private String[] langs = new String[]{
            "Kotlin", 
            "Scala", 
            "Swift",
            "TypeScript"
        };
    
        private String[] descs = new String[]{
            "Kotlin 是运行在 Java 虚拟机上的静态语言,被称之为 Android 世界的 Swift", 
            "Scala 是一门多范式(multi-paradigm)的编程语言", 
            "Swift 是开发 Mac APP 和 iOS APP 的语言",
            "TypeScript 是一种由微软开发的自由和开源的编程语言"
        };
    
        private int[] icons = new int[]{
            R.drawable.kotlin,
            R.drawable.scala,
            R.drawable.swift,
            R.drawable.typescript
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            List<Map<String, Object>> listitem = new ArrayList<Map<String, Object>>();
            for (int i = 0; i < langs.length; i++) {
                Map<String, Object> showitem = new HashMap<String, Object>();
                showitem.put("icon", icons[i]);
                showitem.put("name", langs[i]);
                showitem.put("desc", descs[i]);
                listitem.add(showitem);
            }
    
            //创建一个simpleAdapter
            SimpleAdapter myAdapter = new SimpleAdapter(getApplicationContext(), listitem, R.layout.list_item, new String[]{"icon", "name", "desc"}, new int[]{R.id.icon, R.id.name, R.id.desc});
    
            ListView listView = (ListView) findViewById(R.id.listview);
            listView.setAdapter(myAdapter);
        }
    }
    

SimpleCursorAdapter 适配器

SimpleCursorAdapter 适配器主要用于从 SQLite 中读取数据

废话不多说,直接上范例

见谅,测试机上没有联系人,连唯一的一个都是临时加的

  1. 创建一个 空的 Android 项目 cn.twle.android.SimpleCursorAdapter

  2. 最重要的来了,我们要定义列表中每一行的布局,在 res/layout 目录下新建一个文件 list_item.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"
        android:orientation="horizontal">
    
        <TextView
            android:id="@+id/list_name"
            android:layout_width="0dp"
            android:layout_height="64dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="简单教程"
            android:textColor="#0000FF"
            android:textSize="18sp" />
    
        <TextView
            android:id="@+id/list_phone"
            android:layout_width="0dp"
            android:layout_height="64dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="13888888888"
            android:textColor="#EA5C4D"
            android:textSize="18sp" />
    
    </LinearLayout>
    
  3. 修改 activity_main.xml 添加一个 ListView

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp" 
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    
  4. 修改 MainActivity.java

    package cn.twle.android.simplecursoradapter;
    
    import android.database.Cursor;
    import android.provider.ContactsContract;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    import android.widget.SimpleCursorAdapter;
    
    import android.widget.ListView;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ListView listview = (ListView) findViewById(R.id.listview);
    
            //读取联系人
            Cursor cursor = getContentResolver()
                    .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
    
            SimpleCursorAdapter spcAdapter = new SimpleCursorAdapter(this,R.layout.list_item,cursor,
                    new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER},
                    new int[]{R.id.list_name,R.id.list_phone});
            listview.setAdapter(spcAdapter);
        }
    }
    
  5. 修改 AndroidManifest.xml ,在 </application> 添加读联系人的权限就可以

        </application>
        <uses-permission android:name="android.permission.READ_CONTACTS"/>
    </manifest>
    
  6. 安装的时候要在读取联系人权限的时候点击 允许

注意

使用 SimpleCursorAdapter 的话,绑定的数据库表中一定要有 id 这个字段, 或者 as id;而且在绑定时取出的数据必须包含这个 id 项,否则的话会报以下错误

java.lang.IllegalArgumentException: column 'id' does not exist

参考文档

  1. 官方文档: Adapter

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.