24. 【Android教程】适配器 Adapter

本节将会引入一个全新的概念——适配器,这个名字很形象,和电源适配器的功能类似,从程序设计的角度出发,它可以将不同类型、不同结构的数据适配到一起。
在 Android 中,适配器是 UI 组件和数据之间的桥梁,它帮助我们将数据填充到 UI 组件当中,实现了一个典型的 MVC 模式。我们可以分别编写独立的 UI 样式和数据模型,至于数据如何与 UI 组件绑定都由 Adapter 帮我们完成,这样的好处就是做到 UI 和数据的解耦。Android 系统为我们提供了多种 Adapter,今天就来介绍几种常见同场景下 Adapter 的基本用法。

1. 为什么要用 Adapter

我们首先看看 Android 为什么要引入 Adapter,也就是使用 Adapter 有哪些好处?
在 Android 中Adapter 通常是搭配列表控件使用,我们先看看在没有学习 Adapter 的时候,如何实现一个列表样式,我们可能需要以下几步:

  1. 创建一个 ScrollView(上一节刚学到的,不熟悉的可以参照 22 节);
  2. 在 ScrollView 中放置多个 View / ViewGroup,比如 TextView;
  3. 获取每个 TextView 实例,根据业务需求为 TextView 设置 Text;
  4. 编写额外代码管理所有的 TextView,并且需要分辨点击事件发生在第几行从而定位到相应的 TextView,从而相应列表的点击事件。

读到这里,脑海里已经有实现思路了吗?即使你能捋清思路,代码也很难写的优雅,因为编写 TextView 样式的这些 UI 代码一定会和 TextView 内容的数据代码耦合在一起,这样如何 UI 样式一变,数据也需要做很大的调整,后期的维护成本是相当高的。最好的办法就是能够有一套逻辑专门去管理数据和 UI 代码的绑定关系,用它来将 UI、Data 隔离开,提高代码的简洁性和可维护性。
我们结合一张图来理解一下 Adapter:

电源适配器将电器和电源接口适配到一起,好处是可以让手机等电子产品及家用电器厂商在生产过程中完全不需要考虑用户电源接口的类型,可以是 220V 交流电、也可以是 USB 接口,适配工作只需要交给相应的 Adapter 就可以完成。而 Android 适配器是将数据和 UI 适配到一起,好处同样也是我们在做 UI 的时候,完全不用考虑未来填充的数据是什么样的,只需要针对不同的数据类型提供一个 Adapter 即可。

如果你觉得上面的描述都太抽象,后面可以通过几个简单的例子来直观感受一下 Adapter 的用法。

2. Adapter 的类型

就像电源适配器需要根据不同的电源接口类型提供不同的适配器一样,Android 中我们需要根据不同数据类型提供不同的 Adapter,系统已经为我们实现了几种 Adapter:

  1. BaseAdapter:
    所有 Adapter 的基类,通常我们需要实现自定义 Adapter 时,需要实现此抽象类,在实际开发中使用的最多的类型。
  2. ArrayAdapter:
    适用于一个单项列表,并且数据可以以数据形式存放的场景。
  3. SimpleAdapter:
    适用于一个列表项中有多个数据的场景,它可以将一个 map 里的数据映射到 xml 布局文件中的各个控件上。
  4. SimpleCursorAdapter:
    针对数据库使用的 Adapter,使用场景很少。

3. 常见 Adapter 的用法

其实最常用的是 BaseAdapter,在实际开发中稍微复杂一点的列表都需要通过继承 BaseAdapter 来编写一个自定义的 Adapter 。大多数场景是结合 ListView / GridView 来完成,所以 BaseAdapter 的具体用法我们会放到后面 ListView / GridView 的相关章节做详细介绍,这里主要是让大家对 Adapter 的概念有个基本认识即可。

3.1 ArrayAdapter 的用法

ArrayAdpater 的用法非常简单,如上一小节所说,它适合列表是单项列表并且数据可以存在一个数据当中的场景。首先我们创建布局文件,里面只需要存放一个 ListView 控件即可:

<ListView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/simpleListView"android:layout_width="match_parent"android:layout_height="wrap_content"android:divider="#000"android:dividerHeight="2dp" />

其中有两个属性大家可能比较陌生:

 android:divider="#000"android:dividerHeight="2dp"

这两个属性是用来设置列表项之间的分割线样式的,详细的会在 ListView 章节进行介绍。然后还需要编写列表中每个列表项的布局样式,我们只需要一个 TextView 来显示文本,而文本的内容就是数组的数据,列表项布局代码 list_view.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="vertical"><TextViewandroid:id="@+id/textView"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:padding="30dp"android:textColor="#000" />
</LinearLayout>

一个我们非常熟悉的 TextView,然后就可以在 Java 代码中通过 ArrayAdapter进行数据 / UI 的绑定了,Java 代码如下:

package com.emercy.myapplication;import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;import android.app.Activity;public class MainActivity extends Activity {ListView mList;String mNums[] = {"TextView", "EditText", "Button", "ImageButton", "RadioButton", "ToggleButton","ImageView", "ProgressBar", "SeekBar", "RatingBar", "ScrollView", "Adapter"};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mList = findViewById(R.id.simpleListView);ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this, R.layout.list_view, R.id.textView, mNums);mList.setAdapter(arrayAdapter);}}

我们在 OnCreate() 中获取ListView对象,然后创建 ArrayAdapter,传入列表项的布局文件 ID、需要显示内容的 TextView 控件 ID 以及数组形式的数据。最后通过 setAdapter 完成数据及 UI 的绑定,这样系统就会帮我们完成适配工作,效果如下:

我们写在数组中的数据就会按顺序填充到列表中了。

3.2 SimpleAdapter 的用法

SimpleAdapter 相比 ArrayAdapter 会更丰富一点,主要体现在 ArrayAdapter 只能适用于列表中只有一项数据(上一小节中的 TextView)的场景,而如果列表项由多个数据组成,比如文字配图片的形式 ArrayAdapter 就有些力不从心,这时候就需要用到 SimpleAdapter 了。
整个 Activity 的布局文件依旧不变,只需要放置一个 ListView 即可。我们在之前的list_view.xml中增加一个 ImageView,如下:

<?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="wrap_content"><ImageViewandroid:id="@+id/imageView"android:layout_width="50dp"android:layout_height="50dp"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_marginRight="10dp"android:padding="5dp" /><TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:padding="30dp"android:textColor="#000" />
</RelativeLayout>

从上面的布局文件可以看出,我们现在的列表项由两个部分组成:一个图片和一个文本。接着修改 Java 代码,主要是数据格式的变换,现在数据数组需要包含图片资源和文本内容两个部分,如下:

package com.emercy.myapplication;import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;import java.util.ArrayList;
import java.util.HashMap;public class MainActivity extends Activity {ListView mListView;String[] mDataName = {"苹果", "梨", "香蕉", "桃子", "西瓜", "荔枝", "橘子"};int[] mDataImage = {R.drawable.apple, R.drawable.pear, R.drawable.banana, R.drawable.peach,R.drawable.watermelon, R.drawable.lychee, R.drawable.orange, R.drawable.orange};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mListView = findViewById(R.id.simpleListView);// 将水果图片和水果名称整合到一个map当中,最后将所有的水果都存放到ArrayListArrayList<HashMap<String, String>> arrayList = new ArrayList<>();for (int i = 0; i < mDataName.length; i++) {HashMap<String, String> hashMap = new HashMap<>();hashMap.put("name", mDataName[i]);hashMap.put("image", mDataImage[i] + "");arrayList.add(hashMap);}String[] from = {"name", "image"};int[] to = {R.id.textView, R.id.imageView};SimpleAdapter simpleAdapter = new SimpleAdapter(this, arrayList, R.layout.list_view, from, to);mListView.setAdapter(simpleAdapter);mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {Toast.makeText(getApplicationContext(), mDataName[i], Toast.LENGTH_LONG).show();}});}
}

在这段例子中,我们使用两个数组分别保存水果名称及水果图片,然后再将每个水果的名称和图片存入一个 map,接着把所有的水果 map 都整合到一个 ArrayList 当中,最后创建 SimpleAdapter,这一步也是最关键的。我们来单独看看 SimpleAdapter 的创建语句:

SimpleAdapter simpleAdapter = new SimpleAdapter(this, arrayList, R.layout.list_view, from, to);

SimpleAdapter 构造器参数比较多,我们来仔细分析分析。传入构造器的第二个参数是数据源,也就是存放所有水果 map 的 ArrayList 对象;传入的第三个参数是列表项的布局文件,即 list_view.xml;第四个参数是一个字符串数组,表示水果 map 中的 key,也就是水果名和水果图片的 key,用来与具体的 UI 控件对应;最后一个参数是一个整形数组,用来与第四个参数匹配,告诉系统 map 中的哪些数据需要显示到哪个 View 上。这样一来,就完成了列表、列表项、数据的对应关系,接着直接用setAdapter完成适配,最后通过 ListView 的setOnItemClickListener为每个列表项添加点击事件(具体使用方法会在 ListView 章节详细介绍),效果如下:

4 小结

本节介绍了一个比较新鲜的概念——适配器,大家初期理解它可以当成电源适配器来理解就好。然后介绍了几种常用的使用方法,系统也为我们提供了几种封装好的 Adapter 可以应付一些简单的场景。但是在大家实际的开发过程中能够直接使用系统提供的 Adapter 的场景比较少,大多数情况还是要继承 BaseAdapter 来自己实现一套 Adapter,这个内容会在 ListView / GridView 相关章节做具体的介绍。另外,大家可以思考一下本章节的例子如果使用 ScrollView 要怎么实现,优劣势在哪里?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/619740.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C/C++基础----指针

指针的定义 在c/c中&#xff0c;有一个特殊的变量指向我们电脑中某个内存地址&#xff0c;进而可以让我们操作这段内存&#xff0c;指的就是指针类型 语法&#xff1a; int a 10; int* p &a;&符号是取出某个变量的内存地址 把这个内存地址赋值给一个变量p&#xff…

vscode和pycharm等idea编写protobuf文件格式化

想在pycharm或者goland等idea中开发protobuf文件的话&#xff0c;可以安装一个插件&#xff1a;protocol-buffers 安装之后&#xff0c;proto文件就会支持高亮和格式化了。 如果是vscode想要编写proto文件&#xff0c;可以安装另外一个插件&#xff1a;vscode-proto3 安装后&a…

自定义vue-cli 实现预设模板项目

模板结构 主要包括四个部分&#xff1a; preset.jsonprompts.jsgenerator/index.jstemplate/ 项目最终结构 preset.json preset.json 中是一个包含创建新项目所需预定义选项和插件的 JSON 对象&#xff0c;让用户无需在命令提示中选择它们&#xff0c;简称预设&#xff1b;…

【C 数据结构】栈

文章目录 【 1. 基本原理 】栈的分类 【 2. 动态链表栈 】2.1 双结构体实现2.1.0 栈的节点设计2.1.1 入栈2.1.2 出栈2.1.3 遍历2.1.4 实例 2.2 单结构体实现2.2.0 栈的节点设计2.2.1 入栈2.2.2 出栈2.2.3 实例 【 3. 顺序栈 】3.1 入栈3.2 出栈3.3 实例 【 1. 基本原理 】 栈&…

手机数据恢复工具

下载地址&#xff1a;手机数据恢复工具.zip Android/HarmonyOS 文件误删是日常使用电子设备时经常遇到的问题&#xff0c;也许一不小心就就可能会误删。 俗话说&#xff1a;数据无价&#xff0c;一但想要找回一些被删除的文件&#xff0c;就需要耗费大量的精力和财力来恢复文…

three.js捋文档的记录笔记(六):场景 几何体 材质 物体 相机 渲染器的简单理解

三维场景Scene const scene new THREE.Scene();物体形状&#xff1a;几何体 Geometry //创建一个长方体几何对象Geometry const geometry new THREE.BoxGeometry(100, 100, 100); 物体外观&#xff1a;材质Material //创建一个材质对象Material const material new THREE.M…

锂电池寿命预测 | Matlab基于BiLSTM双向长短期记忆神经网络的锂电池寿命预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 锂电池寿命预测 | Matlab基于BiLSTM双向长短期记忆神经网络的锂电池寿命预测 程序设计 完整程序和数据获取方式&#xff1a;私信博主回复Matlab基于BiLSTM双向长短期记忆神经网络的锂电池寿命预测。 参考资料 [1] h…

自编译支持CUDA硬解的OPENCV和FFMPEG

1 整体思路 查阅opencv的官方文档&#xff0c;可看到有个cudacodec扩展&#xff0c;用他可方便的进行编解码。唯一麻烦的是需要自行编译opencv。 同时&#xff0c;为了考虑后续方便&#xff0c;顺手编译了FFMPEG&#xff0c;并将其与OPENCV绑定。 在之前的博文“鲲鹏主机昇腾A…

家庭网络防御系统搭建-将NDR系统的zeek日志集成到security onion

在前面的文章中安装了zeek,这里&#xff0c;安装了securityonion&#xff0c;这里&#xff0c;本文讲述如何将zeek生成的日志发送到siem security onion之中。 所有日志集成的步骤分为如下几步&#xff1a; 日志收集配置日志发送接收日志解析配置日志展示配置 ZEEK日志收集配…

BackTrader 中文文档(十二)

原文&#xff1a;www.backtrader.com/ Visual Chart 原文&#xff1a;www.backtrader.com/docu/live/vc/vc/ 与 Visual Chart 的集成支持两者&#xff1a; 实时数据提供 实时交易 Visual Chart是完整的交易解决方案&#xff1a; 在单个平台上集成图表、数据源和经纪功能 更多…

第⑭讲:Ceph集群管理:守护进程管理、日志管理和端口号配置

文章目录 1.Ceph各组件守护进程的管理方式2.守护进程管理操作2.1.Ceph所有组件的守护进程列表2.2.重启当前主机中所有的Ceph组件2.3.重启主机中所有的Monitor组件2.4.重启指定主机的Monitor组件2.5.重启指定的OSD组件 3.Ceph的日志管理4.Ceph集群各组件的守护进程5.Ceph集群各组…

通讯录(单链表思想)

文章目录 通讯录 2.0头文件通讯录操作函数通讯录主函数 通讯录 2.0 之前分享过使用顺序表思想实现通讯录&#xff0c;现在分享使用单链表实现的通讯录&#xff0c;我们只需要规定每个链表的元素是结构体类型&#xff0c;每个结构体内存放联系人信息即可。 **不断地练习才能熟练…