学习Android的第十五天

目录

Android Adapter 适配器

MVC 模式

Adapter

ArrayAdapter 泛型

ArrayAdapter 构造函数的第二个参数

范例

SimpleAdapter 适配器

范例

SimpleCursorAdapter 适配器

范例

参考文档


Android Adapter 适配器

Android 中的 Adapter(适配器)是用于在 UI 组件(如 ListView、RecyclerView)和数据之间建立连接的桥梁。它负责将数据源中的数据转换成视图(View),然后将这些视图展示在 UI 组件上供用户查看和操作。

如微信页面中,Adapter 负责将微信中的消息数据转换成合适的视图,并将这些视图显示在列表中。这样用户就可以通过滚动列表查看消息,点击消息进行相应操作等。

Adapter 的主要作用包括:

  1. 将数据源转换成视图:Adapter 从数据源中获取数据,并将其转换成可显示在 UI 组件上的视图。

  2. 管理视图复用:在列表等大量数据的情况下,Adapter 负责管理视图的复用,以减少内存开销和提高性能。

  3. 处理用户交互:Adapter 可以处理用户与列表中项的交互,例如点击、长按等操作。

  4. 提供数据更新机制:Adapter 提供了机制来通知 UI 组件数据的变化,以便及时更新视图。

MVC 模式

为了更好的理解 Adapter 的作用,我们先来了解下 MVC 模式(详细可见此章

MVC(Model-View-Controller)模式是一种软件架构模式,用于将应用程序分成三个核心组件:模型(Model)、视图(View)和控制器(Controller)。每个组件都有不同的职责,彼此之间相互独立,这样可以使代码更易于管理、维护和扩展。

模型(Model)

  • 模型代表应用程序的数据和业务逻辑。
  • 模型负责存储、检索和更新数据,以及执行与数据相关的操作。
  • 模型通常是独立于用户界面的,可以被多个视图共享。
  • 在 Android 中,模型通常表示数据源、数据库、网络请求等。

视图(View)

  • 视图是用户界面的可视化部分,负责向用户展示数据和接收用户输入。
  • 视图通常是模型的直接表示,但不包含任何业务逻辑。
  • 视图是 passives,即 passives 响应控制器或模型的更改,并相应地更新自身。
  • 在 Android 中,视图可以是 Activity、Fragment、XML 布局文件等。

控制器(Controller)

  • 控制器是模型和视图之间的中介,负责协调用户输入、数据更新和视图更新之间的交互。
  • 控制器捕获用户的操作,并根据这些操作更新模型或视图。
  • 控制器可以包含一些业务逻辑,但主要是用来管理应用程序的流程和交互。
  • 在 Android 中,控制器可以是 Activity、Fragment、自定义控制器等。

而Adapter 在某种程度上实现了 MVC 模式中控制器(Controller)的功能,因为它在数据模型和用户界面之间起到了连接的作用。但严格来说,Adapter 更多地用于实现数据与视图之间的适配,而不是控制整个应用程序的逻辑和流程。

Adapter

在 Android 中,Adapter 是一个重要的概念,用于将数据与 UI 组件(如 ListView、RecyclerView)进行连接和适配。

Adapter 的继承关系图

下面是一些常见的 Adapter 类及其继承关系:

BaseAdapter:

  • 抽象类,是 Android 中使用最广泛的 Adapter 之一。
  • 提供了一些基本的实现,但需要开发者自己实现 getCount()、getItem()、getItemId() 和 getView() 等方法。
  • 适用于自定义的数据类型和视图布局。

ArrayAdapter:

  • 继承自 BaseAdapter。
  • 支持泛型操作,可以方便地与数组或列表进行适配。
  • 通常用于展示简单的列表数据,例如只包含一行文字。

SimpleAdapter:

  • 继承自 BaseAdapter。
  • 提供了一种简单而灵活的方式来将数据与视图绑定。
  • 可以自定义多种效果,例如列表项中包含不同的控件(TextView、ImageView 等)。

SimpleCursorAdapter:

  • 继承自 CursorAdapter,间接地实现了 BaseAdapter 接口。
  • 用于将数据库中的查询结果(Cursor)与视图绑定,通常用于显示数据库查询结果。
  • 不推荐使用,因为它不够灵活,只适用于显示简单文本类型的 ListView。

ArrayAdapter 泛型

ArrayAdapter 支持泛型数据,这使得它可以与各种类型的数据集合进行适配,并在 ListView 或 Spinner 等控件中显示。

使用泛型的好处是可以在编译时就进行类型检查,从而提高代码的安全性和可读性。通过将 ArrayAdapter 声明为泛型类,可以指定它要适配的数据类型,以便在使用时编译器可以执行类型检查。

例如,如果有一个包含整数的列表,可以这样使用泛型 ArrayAdapter:

ArrayList<Integer> dataList = new ArrayList<>();
dataList.add(1);
dataList.add(2);
dataList.add(3);

ArrayAdapter<Integer> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, dataList);

这样,当您尝试将不兼容的数据类型添加到 ArrayAdapter 中时,编译器会发出警告或错误,从而帮助您在编译时捕获潜在的类型错误。

使用泛型 ArrayAdapter 可以更加安全和便捷地处理不同类型的数据集合,并在 UI 控件中进行显示。

ArrayAdapter 构造函数的第二个参数

android.R.layout.simple_expandable_list_item_1 是 ArrayAdapter 构造函数的第二个参数,用于指定要为 ListView 中的每个列表项使用的布局模板。

这些布局模板是 Android 系统提供的预定义布局,可以根据需要选择适合的模板来展示列表项。

下面是几种常见的布局模板:

  • android.R.layout.simple_list_item_1:单独一行的文本框,适合用于显示简单的文本信息。
  • android.R.layout.simple_list_item_2:由两个文本框组成的列表项,适合用于显示比较复杂的文本信息,例如标题和副标题。
  • android.R.layout.simple_list_item_checked:每个列表项都包含一个已选中的列表项,通常与 ListView 的选择模式相关联,可用于实现多选列表。
  • android.R.layout.simple_list_item_multiple_choice:每个列表项都带有一个复选框,适合用于实现多选列表。
  • android.R.layout.simple_list_item_single_choice:每个列表项都带有一个单选钮,适合用于实现单选列表。

范例

<?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"
    android:gravity="center">
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</LinearLayout>
package com.example.myapplication;

import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

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

        // 准备数据源
        ArrayList<String> dataList = new ArrayList<>();
        dataList.add("项目 1:Java");
        dataList.add("项目 2:C#");
        dataList.add("项目 3:Python");
        dataList.add("项目 4:C++");
        dataList.add("项目 5:PHP");

        // 实例化 ArrayAdapter
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, dataList);

        // 设置适配器
        ListView listView = findViewById(R.id.listView);
        listView.setAdapter(adapter);
    }
}

SimpleAdapter 适配器

SimpleAdapter 是 Android 中最简单的适配器之一,尽管它简单,但它提供了强大的功能,适用于许多常见的数据展示需求。SimpleAdapter 可以用于将数据源中的数据与 UI 组件(如 ListView)进行绑定,并在列表中显示。

SimpleAdapter 的主要特点和功能包括:

  • 简单易用:SimpleAdapter 的使用非常简单,只需提供数据源和布局资源即可快速实现数据与视图的绑定。
  • 支持多种数据类型:SimpleAdapter 可以适配各种数据类型,包括字符串、整数、图片等。
  • 灵活的布局控制:SimpleAdapter 允许您通过定义布局资源来控制每个列表项的显示内容和样式。
  • 支持多种视图类型:SimpleAdapter 支持在列表中显示多种类型的视图,例如 TextView、ImageView 等。
  • 数据更新方便:SimpleAdapter 提供了便捷的方法来更新数据源,使得数据的动态更新变得简单。

虽然 SimpleAdapter 功能简单,但在许多场景下都可以满足基本的需求,特别是对于那些不需要复杂定制的列表展示,SimpleAdapter 是一个非常方便的选择。

范例

<?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"
    android:gravity="center">
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</LinearLayout>
package com.example.myapplication;

import android.os.Bundle;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

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

        // 准备数据源
        List<Map<String, String>> dataList = new ArrayList<>();
        Map<String, String> item1 = new HashMap<>();
        item1.put("title", "项目1");
        item1.put("subtitle", "项目1的副标题");
        dataList.add(item1);

        Map<String, String> item2 = new HashMap<>();
        item2.put("title", "项目2");
        item2.put("subtitle", "项目2的副标题");
        dataList.add(item2);

        // 定义布局资源
        int layoutResource = android.R.layout.simple_list_item_2;

        // 定义数据源中的键名
        String[] from = {"title", "subtitle"};

        // 定义布局资源中的控件 id
        int[] to = {android.R.id.text1, android.R.id.text2};

        // 实例化 SimpleAdapter
        SimpleAdapter adapter = new SimpleAdapter(this, dataList, layoutResource, from, to);

        // 设置适配器
        ListView listView = findViewById(R.id.listView);
        listView.setAdapter(adapter);
    }
}

效果图:

SimpleCursorAdapter 适配器

SimpleCursorAdapter 是用于将数据库查询结果(Cursor)与视图控件(如 ListView)进行绑定的适配器。它主要用于从 SQLite 数据库中读取数据并将其显示在 UI 控件中。

范例

<?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"
    android:gravity="center">
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</LinearLayout>
package com.example.myapplication;

import android.Manifest;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class MainActivity extends AppCompatActivity {
    private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;
    private ListView listView;
    private SimpleCursorAdapter adapter;

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

        listView = findViewById(R.id.listView);

        // 检查是否有读取联系人权限,如果没有则请求权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_CONTACTS},
                    PERMISSIONS_REQUEST_READ_CONTACTS);
        } else {
            // 如果已经有权限,直接加载联系人数据
            loadContacts();
        }
    }

    private void loadContacts() {
        // 定义要查询的字段
        String[] projection = {ContactsContract.Contacts._ID,
                ContactsContract.Contacts.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER};

        // 查询联系人
        Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                projection, null, null, null);

        // 定义要显示的字段
        String[] fromColumns = {ContactsContract.Contacts.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER};
        int[] toViews = {android.R.id.text1, android.R.id.text2};

        // 实例化 SimpleCursorAdapter,并将数据绑定到 ListView
        adapter = new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_2, cursor,
                fromColumns, toViews, 0);
        listView.setAdapter(adapter);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 用户同意了权限请求,加载联系人数据
                loadContacts();
            } else {
                // 用户拒绝了权限请求,显示提示信息
                Toast.makeText(this, "无法读取联系人,因为未授予权限", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

最后在 AndroidManifest.xml 文件中,添加了读取联系人权限的声明: 

    </application>
    <uses-permission android:name="android.permission.READ_CONTACTS"/>

</manifest>

打开模拟机的时候要在读取联系人权限的时候点击 OK

参考文档

官方文档: Adapter

  • 31
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员老李头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值