Android适配器完全指南:从入门到精通

目录

一、Adapter 核心原理

二、常见 Adapter 类型及典型用法

1. ArrayAdapter:简单文本列表(适合 ListView/Spinner)

适用场景:

基本用法(绑定 ListView):

自定义列表项布局:

2. SimpleAdapter:多元素列表(适合 ListView)

适用场景:

基本用法:

局限性:

3. BaseAdapter:完全自定义列表(适合 ListView)

适用场景:

核心方法:

基本用法(自定义对象 + 优化复用):

关键优化:ViewHolder 模式

4. RecyclerView.Adapter:高性能复杂列表(适合 RecyclerView)

适用场景:

核心方法:

基本用法:

优势:

三、Adapter 通用操作:数据更新

四、总结


在 Android 开发中,Adapter(适配器)是数据与 UI 之间的桥梁,核心作用是将复杂数据(如列表、集合)按照指定的 UI 布局(如列表项)展示在可滚动控件(如 ListViewRecyclerViewSpinner 等)上。它解决了 “数据格式” 与 “UI 展示” 的解耦问题,让数据更新时无需手动操作 UI,只需更新数据源并通知适配器即可。

一、Adapter 核心原理

  • 数据(Model):需要展示的数据(如 List<User>List<String>)。
  • UI 视图(View):列表项的布局(如 item_user.xml),定义每个列表项的样式。
  • Adapter 角色
    1. 管理数据(获取数据数量、单个数据);
    2. 将数据绑定到列表项视图(把数据填充到布局的控件中);
    3. 复用视图(避免频繁创建视图导致的性能问题)。

二、常见 Adapter 类型及典型用法

根据适配的控件和功能,Android 提供了多种内置 Adapter,也支持自定义 Adapter。以下是最常用的类型及用法:

1. ArrayAdapter:简单文本列表(适合 ListView/Spinner

ArrayAdapter 是最简单的适配器,适用于数据为单一文本的场景(如字符串列表),可直接绑定到 ListView 或 Spinner,无需自定义布局(或仅需简单布局)。

适用场景:
  • 展示纯文本列表(如设置项、选项列表)。
  • 数据类型为 String 或可转为字符串的对象(重写 toString() 方法)。
基本用法(绑定 ListView):

java

运行

// 1. 数据源(字符串列表)
List<String> data = new ArrayList<>();
data.add("张三");
data.add("李四");
data.add("王五");

// 2. 创建 ArrayAdapter(参数:上下文、列表项布局、数据)
// 注:android.R.layout.simple_list_item_1 是系统内置的简单文本布局
ArrayAdapter<String> adapter = new ArrayAdapter<>(
    this, 
    android.R.layout.simple_list_item_1, // 列表项布局(仅一个 TextView)
    data 
);

// 3. 绑定到 ListView
ListView listView = findViewById(R.id.list_view);
listView.setAdapter(adapter);
自定义列表项布局:

若需简单修改文本样式(如颜色、大小),可自定义列表项布局(仅含 TextView):

xml

<!-- res/layout/item_text.xml -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tv_text"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center_vertical"
    android:paddingLeft="16dp"
    android:textColor="#FF0000"
    android:textSize="18sp"/>

代码中使用自定义布局:

java

运行

ArrayAdapter<String> adapter = new ArrayAdapter<>(
    this, 
    R.layout.item_text, // 自定义布局
    R.id.tv_text, // 布局中 TextView 的 ID
    data 
);
listView.setAdapter(adapter);
2. SimpleAdapter:多元素列表(适合 ListView

SimpleAdapter 支持多控件的列表项布局(如包含图片 + 文本 + 按钮),数据源需为 List<Map<String, Object>>(键值对集合),通过键名绑定布局中的控件。

适用场景:
  • 列表项包含多种元素(如图标 + 标题 + 描述),且逻辑简单(无需复杂交互)。
基本用法:

java

运行

// 1. 数据源(每个元素是一个 Map,存储列表项的多组数据)
List<Map<String, Object>> data = new ArrayList<>();
for (int i = 0; i < 3; i++) {
    Map<String, Object> item = new HashMap<>();
    item.put("icon", R.drawable.ic_user); // 图标资源 ID
    item.put("name", "用户" + i); // 名称
    item.put("desc", "这是用户" + i + "的描述"); // 描述
    data.add(item);
}

// 2. 列表项布局(含 ImageView + 两个 TextView)
// res/layout/item_user.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="80dp"
    android:gravity="center_vertical"
    android:padding="16dp">

    <ImageView
        android:id="@+id/iv_icon"
        android:layout_width="40dp"
        android:layout_height="40dp"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:textStyle="bold"/>

        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            android:textSize="14sp"
            android:textColor="#999"/>
    </LinearLayout>
</LinearLayout>

// 3. 创建 SimpleAdapter(参数说明见注释)
SimpleAdapter adapter = new SimpleAdapter(
    this,
    data, // 数据源(List<Map>)
    R.layout.item_user, // 列表项布局
    new String[]{"icon", "name", "desc"}, // Map 中的键名数组(与数据对应)
    new int[]{R.id.iv_icon, R.id.tv_name, R.id.tv_desc} // 布局中控件的 ID 数组(与键名一一对应)
);

// 4. 绑定到 ListView
ListView listView = findViewById(R.id.list_view);
listView.setAdapter(adapter);
局限性:
  • 仅支持简单数据绑定,无法处理复杂交互(如按钮点击事件);
  • 数据源必须是 List<Map>,灵活性较低。
3. BaseAdapter:完全自定义列表(适合 ListView

BaseAdapter 是抽象类,需重写核心方法实现完全自定义,支持任意复杂的列表项布局和交互逻辑(如动态数据、按钮点击、多种布局类型),是 ListView 场景下最常用的适配器。

适用场景:
  • 列表项布局复杂(多控件、动态样式);
  • 需要处理列表项内部的交互(如按钮点击、复选框选择);
  • 数据源类型复杂(如自定义对象 UserProduct)。
核心方法:

继承 BaseAdapter 需重写以下 4 个方法:

  • getCount():返回数据总数(决定列表项数量);
  • getItem(int position):返回指定位置的数据对象;
  • getItemId(int position):返回指定位置的 ID(通常返回 position);
  • getView(int position, View convertView, ViewGroup parent)核心方法,返回列表项视图,负责将数据绑定到视图。
基本用法(自定义对象 + 优化复用):

以展示 User 对象列表为例,包含性能优化(ViewHolder 模式):

java

运行

// 1. 自定义数据类(User)
public class User {
    private int icon; // 头像资源 ID
    private String name; // 姓名
    private String phone; // 电话

    public User(int icon, String name, String phone) {
        this.icon = icon;
        this.name = name;
        this.phone = phone;
    }

    // getter 方法
    public int getIcon() { return icon; }
    public String getName() { return name; }
    public String getPhone() { return phone; }
}

// 2. 列表项布局(res/layout/item_user.xml)
// 结构:ImageView(头像) + 两个 TextView(姓名、电话)
<?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="60dp"
    android:gravity="center_vertical"
    android:padding="16dp">

    <ImageView
        android:id="@+id/iv_icon"
        android:layout_width="40dp"
        android:layout_height="40dp"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"/>

        <TextView
            android:id="@+id/tv_phone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="2dp"
            android:textSize="12sp"
            android:textColor="#666"/>
    </LinearLayout>
</LinearLayout>

// 3. 自定义 BaseAdapter(含 ViewHolder 优化)
public class UserAdapter extends BaseAdapter {
    private Context context;
    private List<User> dataList; // 数据源

    // 构造方法:传入上下文和数据
    public UserAdapter(Context context, List<User> dataList) {
        this.context = context;
        this.dataList = dataList;
    }

    // 返回数据总数
    @Override
    public int getCount() {
        return dataList.size();
    }

    // 返回指定位置的数据
    @Override
    public Object getItem(int position) {
        return dataList.get(position);
    }

    // 返回指定位置的 ID(通常用 position)
    @Override
    public long getItemId(int position) {
        return position;
    }

    // 核心:获取列表项视图并绑定数据
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        // 1. 复用视图:convertView 为 null 时创建新视图,否则复用
        if (convertView == null) {
            // 加载布局
            convertView = LayoutInflater.from(context)
                    .inflate(R.layout.item_user, parent, false);
            // 创建 ViewHolder 存储控件引用
            holder = new ViewHolder();
            holder.ivIcon = convertView.findViewById(R.id.iv_icon);
            holder.tvName = convertView.findViewById(R.id.tv_name);
            holder.tvPhone = convertView.findViewById(R.id.tv_phone);
            // 将 ViewHolder 绑定到 convertView
            convertView.setTag(holder);
        } else {
            // 复用已有的 ViewHolder
            holder = (ViewHolder) convertView.getTag();
        }

        // 2. 绑定数据到控件
        User user = dataList.get(position);
        holder.ivIcon.setImageResource(user.getIcon());
        holder.tvName.setText(user.getName());
        holder.tvPhone.setText(user.getPhone());

        return convertView;
    }

    // ViewHolder 内部类:存储列表项中的控件引用,避免重复 findViewById(性能优化)
    static class ViewHolder {
        ImageView ivIcon;
        TextView tvName;
        TextView tvPhone;
    }
}

// 4. 在 Activity 中使用适配器
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化数据
        List<User> userList = new ArrayList<>();
        userList.add(new User(R.drawable.ic_user1, "张三", "13800138000"));
        userList.add(new User(R.drawable.ic_user2, "李四", "13900139000"));

        // 创建适配器并绑定到 ListView
        ListView listView = findViewById(R.id.list_view);
        UserAdapter adapter = new UserAdapter(this, userList);
        listView.setAdapter(adapter);
    }
}
关键优化:ViewHolder 模式
  • 问题getView 会频繁调用(滚动列表时),若每次都通过 findViewById 获取控件,会导致性能损耗。
  • 解决:用 ViewHolder 存储控件引用,绑定到 convertView 的 tag 中,复用视图时直接从 ViewHolder 获取控件,避免重复查找。
4. RecyclerView.Adapter:高性能复杂列表(适合 RecyclerView

RecyclerView 是 Android 推荐的列表控件(替代 ListView),其配套的 RecyclerView.Adapter 支持更灵活的布局(线性、网格、瀑布流)、动画效果和多类型列表项,性能更优。

适用场景:
  • 复杂列表(如社交 APP 的动态流、电商商品列表);
  • 需要多种列表项布局(如一条文本、一条图文、一条视频);
  • 需支持动画(增删项动画、滚动动画)。
核心方法:

RecyclerView.Adapter 是抽象类,需定义一个 ViewHolder 子类,并重写 3 个核心方法:

  • onCreateViewHolder(ViewGroup parent, int viewType):创建 ViewHolder(加载布局、初始化控件);
  • onBindViewHolder(ViewHolder holder, int position):绑定数据到 ViewHolder 的控件;
  • getItemCount():返回数据总数。
基本用法:

java

运行

// 1. 数据类(同 BaseAdapter 示例的 User)
public class User { ... }

// 2. 列表项布局(res/layout/item_user.xml,同上)

// 3. 自定义 ViewHolder(继承 RecyclerView.ViewHolder)
public class UserViewHolder extends RecyclerView.ViewHolder {
    ImageView ivIcon;
    TextView tvName;
    TextView tvPhone;

    public UserViewHolder(View itemView) {
        super(itemView);
        // 初始化控件
        ivIcon = itemView.findViewById(R.id.iv_icon);
        tvName = itemView.findViewById(R.id.tv_name);
        tvPhone = itemView.findViewById(R.id.tv_phone);
    }
}

// 4. 自定义 RecyclerView.Adapter
public class UserRecyclerAdapter extends RecyclerView.Adapter<UserViewHolder> {
    private Context context;
    private List<User> dataList;

    public UserRecyclerAdapter(Context context, List<User> dataList) {
        this.context = context;
        this.dataList = dataList;
    }

    // 创建 ViewHolder(加载布局)
    @Override
    public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context)
                .inflate(R.layout.item_user, parent, false);
        return new UserViewHolder(view);
    }

    // 绑定数据到 ViewHolder
    @Override
    public void onBindViewHolder(UserViewHolder holder, int position) {
        User user = dataList.get(position);
        holder.ivIcon.setImageResource(user.getIcon());
        holder.tvName.setText(user.getName());
        holder.tvPhone.setText(user.getPhone());
    }

    // 返回数据总数
    @Override
    public int getItemCount() {
        return dataList.size();
    }
}

// 5. 在 Activity 中使用(需设置 LayoutManager)
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化数据
        List<User> userList = new ArrayList<>();
        userList.add(new User(R.drawable.ic_user1, "张三", "13800138000"));
        userList.add(new User(R.drawable.ic_user2, "李四", "13900139000"));

        // 初始化 RecyclerView
        RecyclerView recyclerView = findViewById(R.id.recycler_view);
        // 设置布局管理器(必须!决定列表排列方式:线性、网格等)
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        // 设置适配器
        UserRecyclerAdapter adapter = new UserRecyclerAdapter(this, userList);
        recyclerView.setAdapter(adapter);
    }
}
优势:
  • 强制 ViewHolder:必须通过 ViewHolder 管理控件,避免性能问题;
  • 支持多布局类型:重写 getItemViewType(int position) 可返回不同布局类型,在 onCreateViewHolder 中加载对应布局;
  • 动画支持:默认支持增删项动画,可自定义;
  • 布局灵活:通过 LayoutManager 切换线性、网格(GridLayoutManager)、瀑布流(StaggeredGridLayoutManager)布局。

三、Adapter 通用操作:数据更新

当数据源发生变化(增、删、改)时,需通知适配器更新 UI,避免数据与视图不一致。不同 Adapter 的通知方法类似:

java

运行

// 1. 更新数据源(如添加一条数据)
dataList.add(new User(...));

// 2. 通知适配器更新(核心)
adapter.notifyDataSetChanged(); // 刷新所有数据(效率低,适合批量更新)

// 3. 局部更新(仅 RecyclerView.Adapter支持,效率高)
adapter.notifyItemInserted(position); // 插入一条数据
adapter.notifyItemRemoved(position); // 删除一条数据
adapter.notifyItemChanged(position); // 更新一条数据

注意:notifyDataSetChanged() 会刷新整个列表,效率较低;RecyclerView.Adapter 的局部更新方法(如 notifyItemInserted)仅刷新变化的项,性能更优。

四、总结

Adapter 是 Android 列表控件的核心组件,选择合适的 Adapter 可显著提升开发效率和性能:

Adapter 类型适用控件适用场景优势局限性
ArrayAdapterListView/Spinner纯文本列表用法简单,无需自定义仅支持文本,灵活性低
SimpleAdapterListView多控件简单列表(无复杂交互)支持多元素布局,无需写适配器类数据源必须为 List<Map>,不支持复杂交互
BaseAdapterListView复杂列表(自定义布局 + 交互)完全自定义,灵活度高需手动实现优化(如 ViewHolder)
RecyclerView.AdapterRecyclerView高性能复杂列表(多布局、动画、网格等)强制优化,支持多布局和动画,性能最优需配合 LayoutManager,代码稍多

实际开发中,RecyclerView.Adapter 是首选,因其功能全面、性能优异,适合绝大多数列表场景;简单文本列表可使用 ArrayAdapter 快速实现。核心原则是:数据与 UI 分离,通过适配器统一管理绑定逻辑,并做好视图复用优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值