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 的简单使用
-
创建一个 空的 Android 项目
cn.twle.android.ArrayAdapter
-
修改
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,这里先用起来再说
-
修改
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 文件来定义
-
创建一个 空的 Android 项目
cn.twle.android.ArrayAdapter
-
在
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>
-
然后修改
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 设置的模板,有好几种
-
simple_list_item_1
单独一行的文本框
-
simple_list_item_2
两个文本框组成
-
simple_list_item_checked
每项都是由一个已选中的列表项
-
simple_list_item_multiple_choice
都带有一个复选框
-
simple_list_item_single_choice
都带有一个单选钮
SimpleAdapter 适配器
SimpleAdapter 适配器是最简单的 Adapter,虽然简单,但功能一点也没垫底
废话不说,直接上效果图
-
创建一个 空的 Android 项目
cn.twle.android.SimpleAdapter
-
下载 /static/i/android/it_language_icon.zip 解压并把所有的图片拖到
res/drawable
目录 -
修改
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>
-
最重要的来了,我们要定义列表中每一行的布局,在
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>
布局很简单,复杂一点的都用注释说清楚了
-
修改
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 中读取数据
废话不多说,直接上范例
见谅,测试机上没有联系人,连唯一的一个都是临时加的
-
创建一个 空的 Android 项目
cn.twle.android.SimpleCursorAdapter
-
最重要的来了,我们要定义列表中每一行的布局,在
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>
-
修改
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>
-
修改 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); } }
-
修改
AndroidManifest.xml
,在</application>
添加读联系人的权限就可以</application> <uses-permission android:name="android.permission.READ_CONTACTS"/> </manifest>
-
安装的时候要在读取联系人权限的时候点击 允许
注意
使用
SimpleCursorAdapter
的话,绑定的数据库表中一定要有 id 这个字段, 或者 as id;而且在绑定时取出的数据必须包含这个 id 项,否则的话会报以下错误java.lang.IllegalArgumentException: column 'id' does not exist
参考文档
- 官方文档: Adapter