ListView 与 Adapter 适配器入门:从 ArrayAdapter 到 BaseAdapter 的简单介绍
1. ListView 与 Adapter 到底谁在管数据Android 列表入门第一课ListView 是 Android 里最经典的滚动列表控件它能做什么把一堆结构相同的数据字符串、键值对、自定义对象按行铺开超出屏幕后可以上下滑动。适合谁刚学完 Activity 和基础控件、想搞懂「数据怎么变成一行行界面」的初学者。核心检索词就三个ListView、Adapter、适配器绑定关系。很多人第一次写列表会卡在同一个地方明明把数据塞进了 ListView界面却一片空白。原因几乎都是没理解 Adapter 的角色。你可以把 ListView 想成一个空货架它只负责「摆」和「滚动」完全不知道要摆什么。Adapter 则是理货员它拿着你的数据源按行生成一个个 View再交给 ListView 去展示。没有理货员货架永远是空的。所以绑定关系是这条链数据源 → Adapter → ListView.setAdapter()。数据源可以是 String[]、List、List自定义对象Adapter 决定了每一行长什么样、显示哪些字段。Android 官方提供了多种 Adapter入门阶段最常接触的是 ArrayAdapter、SimpleAdapter、BaseAdapter 这三种它们的能力从弱到强写法从简到繁。我试过把这三个放在同一个项目里对比结论很清晰ArrayAdapter 适合纯文本单行SimpleAdapter 适合「多字段但布局固定」的键值对BaseAdapter 适合自定义对象、要放图片或复杂控件、还要做性能优化的场景。下面按这个顺序逐个拆每个都给可直接复制的布局和代码最后附运行验证步骤。需要说明的是本文所有代码基于 Android Studio 默认工程结构包名用 com.example.listviewdemo 演示你替换成自己的即可。布局文件放在 res/layout 下图片资源放 res/drawable。跑通一个可滚动列表从下一节开始动手。2. 三种 Adapter 的适用场景与差异对照ArrayAdapter、SimpleAdapter、BaseAdapter 怎么选在动手写代码前先把三者的定位讲清楚这样你写的时候知道自己在干什么而不是照抄。ArrayAdapter 是最轻的适配器。它的数据源通常是一个数组或 List每一项是一个对象默认把对象的 toString() 结果塞进一个 TextView。系统自带了几种 item 布局比如 android.R.layout.simple_list_item_1 就是「一行一个 TextView」。它的优点是三行代码就能出列表缺点是只能显示单一文本想加第二个控件就得自己写布局而 ArrayAdapter 对自定义布局的支持比较别扭。SimpleAdapter 的数据源是 List也就是一串键值对。你告诉它用哪些 key 取数据、对应 item 布局里哪些控件 id。它内部帮你完成「取值 → 塞进控件」的映射。优点是布局可以自定义、多字段映射不用写循环缺点是数据类型被限制在 Map 里遇到自定义对象要先转成 Map而且图片这类资源处理起来不直观。BaseAdapter 是抽象基类前面两个其实都继承自它。它要求你重写四个方法getCount()、getItem()、getItemId()、getView()。getCount 告诉 ListView 一共多少行getView 负责「给我第 position 行的 View」。因为完全自己控制所以能放任意控件、绑定任意对象、做 convertView 复用优化。缺点是代码量最大初学者容易在 getView 里踩坑。用一张表对照更直观维度ArrayAdapterSimpleAdapterBaseAdapter数据源数组 / ListList任意 Listitem 布局系统默认或简单自定义自定义完全自定义显示字段单文本多字段键值对任意支持图片不方便不直观支持代码量最少中等最多适用场景纯文字列表固定多字段列表复杂/自定义对象选择逻辑可以记成一句话能简单就别复杂。纯文字用 ArrayAdapter两三个文本字段用 SimpleAdapter要图片、要按钮、要性能优化直接上 BaseAdapter。接下来三节分别给出完整可运行代码。3. ArrayAdapter 与 SimpleAdapter 可复制配置布局 XML 加 Java 适配器代码先建工程然后在 res/layout/activity_main.xml 里放一个 ListView。这个布局三个示例共用直接复制?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical ListView android:idid/lv_id android:layout_widthmatch_parent android:layout_heightmatch_parent / /LinearLayout3.1 ArrayAdapter 示例数据源用字符串数组item 用系统自带的 simple_list_item_1。MainActivity.javapackage com.example.listviewdemo; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private ListView mListView; private String[] data {item_One, item_Two, item_Three, item_Four, item_Five, item_Six, item_Seven, item_Eight, item_Nine, item_Ten}; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView findViewById(R.id.lv_id); // 参数1 上下文参数2 item 布局参数3 数据源 ArrayAdapterString adapter new ArrayAdapter( this, android.R.layout.simple_list_item_1, data); mListView.setAdapter(adapter); } }运行后你会看到十行文字可以上下滑动。这就是最小可用的列表。3.2 SimpleAdapter 示例SimpleAdapter 需要自定义 item 布局因为要放两个 TextView。新建 res/layout/listview_item.xml?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationvertical android:padding12dp TextView android:idid/text_one android:layout_widthmatch_parent android:layout_heightwrap_content android:textSize16sp android:textColor#222222 / TextView android:idid/text_two android:layout_widthmatch_parent android:layout_heightwrap_content android:textSize14sp android:textColor#888888 / /LinearLayoutMainActivity 里构造 ListHashMapString,String再交给 SimpleAdapterpackage com.example.listviewdemo; 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; public class MainActivity extends AppCompatActivity { private ListView mListView; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView findViewById(R.id.lv_id); ListHashMapString, String data new ArrayList(); for (int i 1; i 18; i) { HashMapString, String map new HashMap(); map.put(key_one, dataOne_ i); map.put(key_two, dataTwo_ i); data.add(map); } // 参数4 是 map 的 key 数组参数5 是对应的控件 id 数组顺序一一对应 SimpleAdapter adapter new SimpleAdapter( this, data, R.layout.listview_item, new String[]{key_one, key_two}, new int[]{R.id.text_one, R.id.text_two}); mListView.setAdapter(adapter); } }注意参数 4 和参数 5 是严格按位置对应的key_one 的值进 text_onekey_two 的值进 text_two。写反了数据就会串位这是新手最常见的错误之一。4. BaseAdapter 自定义适配器完整写法getView 复用与运行验证步骤BaseAdapter 是重点也是面试和实战里用得最多的。我们做一个学生信息列表每行显示姓名、年龄和一张头像。先定义数据类 StudentData.javapackage com.example.listviewdemo; public class StudentData { private String name; private int age; private int photo; public String getName() { return name; } public void setName(String name) { this.name name; } public int getAge() { return age; } public void setAge(int age) { this.age age; } public int getPhoto() { return photo; } public void setPhoto(int photo) { this.photo photo; } }item 布局 listview_item.xml 换成带 ImageView 的版本?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationhorizontal android:gravitycenter_vertical android:padding12dp ImageView android:idid/photo_id android:layout_width48dp android:layout_height48dp android:scaleTypecenterCrop / LinearLayout android:layout_width0dp android:layout_heightwrap_content android:layout_weight1 android:orientationvertical android:layout_marginStart12dp TextView android:idid/text_name android:layout_widthwrap_content android:layout_heightwrap_content android:textSize16sp android:textColor#222222 / TextView android:idid/text_age android:layout_widthwrap_content android:layout_heightwrap_content android:textSize14sp android:textColor#888888 / /LinearLayout /LinearLayout自定义适配器 MyListAdapter.java这里用 convertView 复用避免重复 inflatepackage com.example.listviewdemo; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import java.util.List; public class MyListAdapter extends BaseAdapter { private ListStudentData mStudentDataList; private LayoutInflater inflater; public MyListAdapter(ListStudentData list, Context context) { this.mStudentDataList list; this.inflater LayoutInflater.from(context); } Override public int getCount() { return mStudentDataList null ? 0 : mStudentDataList.size(); } Override public Object getItem(int position) { return mStudentDataList.get(position); } Override public long getItemId(int position) { return position; } Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView null) { convertView inflater.inflate(R.layout.listview_item, parent, false); holder new ViewHolder(); holder.tvName convertView.findViewById(R.id.text_name); holder.tvAge convertView.findViewById(R.id.text_age); holder.imPhoto convertView.findViewById(R.id.photo_id); convertView.setTag(holder); } else { holder (ViewHolder) convertView.getTag(); } StudentData data mStudentDataList.get(position); holder.tvName.setText(data.getName()); holder.tvAge.setText(age: data.getAge()); holder.imPhoto.setImageResource(data.getPhoto()); return convertView; } static class ViewHolder { TextView tvName; TextView tvAge; ImageView imPhoto; } }MainActivity 里初始化数据并绑定package com.example.listviewdemo; import android.os.Bundle; import android.widget.ListView; import androidx.appcompat.app.AppCompatActivity; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private ListView mListView; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView findViewById(R.id.lv_id); ListStudentData list new ArrayList(); for (int i 1; i 18; i) { StudentData s new StudentData(); s.setName(lum i 号); s.setAge(i); s.setPhoto(R.drawable.lum); // 换成你自己的图片资源名 list.add(s); } MyListAdapter adapter new MyListAdapter(list, this); mListView.setAdapter(adapter); } }运行验证步骤把图片放进 res/drawable 并命名为 lum.png点击 Android Studio 的 Run模拟器启动后应看到 18 行每行有头像、姓名、年龄上下滑动流畅。如果图片没显示先检查资源名拼写和 R.drawable.lum 是否报红。5. 本篇常见报错排查从 NullPointerException 到列表空白逐条对照列表跑不起来报错往往集中在几个固定位置。下面按真实报错对照排查。第一个高频问题是列表一片空白日志没有崩溃。原因通常是 setAdapter 没调用或者数据源 size 为 0。检查你的 getCount() 是否返回了正确数量ArrayAdapter 场景检查数组是否为空。还有一种情况是 ListView 被外层布局高度压成了 0确认 layout_height 是 match_parent 或具体值。第二个是 NullPointerException 指向 getView 里的 findViewById。这几乎都是 convertView 为 null 时忘了 inflate或者 ViewHolder 没 setTag 就直接 getTag。对照上一节代码确保 inflate 的第二个参数传了 parent、第三个参数传 false这样布局的 LayoutParams 才正确。第三个是数据串位滑动后某几行的文字变成别人的。这是 convertView 复用后没有重新 setText 导致的。复用的 View 带着旧数据你必须在 getView 里对每个控件重新赋值不能只在 convertView null 的分支里设置。第四个是 SimpleAdapter 显示不出内容。检查参数 4 的 key 数组和 map 里 put 的 key 是否完全一致大小写都算再检查参数 5 的控件 id 是否存在于 item 布局里。key 对不上取出来就是 null控件自然空白。第五个是图片不显示或报 Resources$NotFoundException。确认图片确实在 res/drawable 下文件名只能是小写字母、数字、下划线不能有大写和横线。R.drawable.lum 要和文件名严格对应。第六个是点击无响应。ListView 的 item 点击需要在 Adapter 的 getView 返回的根布局上可点击如果 item 里有 Button 这类抢占焦点的控件会吃掉点击事件。入门阶段先别在 item 里放 Button或者给 Button 设 focusablefalse。排查顺序建议先看 Logcat 有没有崩溃栈定位到具体行没崩溃就看数据源 size再确认 setAdapter 执行了最后检查布局层级和控件 id。按这个顺序九成问题能自己解决。6. 从跑通到用顺ListView 适配器入门后的下一步三个示例跑通后你已经掌握了 ListView 和 Adapter 的核心绑定关系。接下来可以做的练习把 ArrayAdapter 的数据换成从网络或数据库读出来的 List给 BaseAdapter 的 item 加点击回调用接口把 position 传回 Activity把 convertView 复用逻辑再检查一遍理解为什么它能减少内存抖动。如果你在配置环境或调试适配器时需要查文档、验证模型输出可以用 TaoToken 的模型对话快速问一些 API 用法和报错含义接入文档在 https://taotoken.net/api 有说明API Key 在 https://taotoken.net/api-keys 获取。长期写 Android 项目、需要稳定调用编码模型的可以看 Coding Planhttps://taotoken.net/coding-plan 。这些只是辅助工具核心还是把 getView 的复用逻辑亲手写几遍。最后留一个实用技巧调试 BaseAdapter 时在 getView 第一行打 Log.d(Adapter, position position convertView (convertView null))滑动列表观察日志你能直观看到哪些行复用了旧 View。这个习惯能帮你彻底搞懂 ListView 的回收机制也为以后学 RecyclerView 打好底子。

相关新闻

人脸门禁系统通信协议选型:HTTP API与MQTT分段架构实战

人脸门禁系统通信协议选型:HTTP API与MQTT分段架构实战

1. 人脸门禁系统的通信架构选型思路人脸门禁这个场景,看起来只是“刷脸开门”四个字,但真正落到工程实施层面,最容易被低估的就是设备端和平台端之间的通信链路设计。我做过好几个园区、写字楼、学校宿舍的人脸门禁项目,踩过最大的…

2026/10/3 19:41:12 阅读更多 →
3分钟落地 Hermes Agent:Windows 环境一站式搭建与 TaoToken 接入指南

3分钟落地 Hermes Agent:Windows 环境一站式搭建与 TaoToken 接入指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 19:43:05 阅读更多 →
UPS机房监控升级实践:干接点告警与Modbus RTU双链路方案详解

UPS机房监控升级实践:干接点告警与Modbus RTU双链路方案详解

两台UPS正常运行时,你会觉得机房稳得不行。可真到凌晨两点十七分,一路市电突然中断,UPS转电池供电,两分钟后电池电压跌破告警线,核心交换机开始陆续重启——而你人在家里,手机上只收到一条冷冰冰的"环…

2026/10/4 19:42:23 阅读更多 →

最新新闻

Telerik Reporting 2023 R2升级实战:前后端兼容与Linux部署避坑

Telerik Reporting 2023 R2升级实战:前后端兼容与Linux部署避坑

最近接了内部管理系统的报表升级任务,要把 Telerik Reporting 从老版本整体迁到 2023 R2,同时解决前端页面白屏、报表服务 404、导出 PDF 在 Linux 服务器上乱码这一串前后端兼容性问题。折腾完那段日子,最大的感受是:这版升级根本…

2026/10/5 3:53:15 阅读更多 →
Java聊天系统设计与实现:Socket多线程通信、JDBC数据库落地与避坑指南

Java聊天系统设计与实现:Socket多线程通信、JDBC数据库落地与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:53:15 阅读更多 →
LUNA16肺结节3D分割一站式:数据准备到推理后处理全流程解析

LUNA16肺结节3D分割一站式:数据准备到推理后处理全流程解析

简介:基于 Pytorch 的 3D 图像分割任务完整工程包,面向医学图像处理与深度学习开发者,以 Luna16 CT 肺结节数据为案例,系统呈现数据准备、模型搭建、训练、验证、测试、评估、可视化与后处理的完整代码思路。资源共 92 个文件&…

2026/10/5 3:53:15 阅读更多 →
Django Rest Framework 实战:从项目设计到性能优化的完整指南

Django Rest Framework 实战:从项目设计到性能优化的完整指南

Django Rest Framework(DRF)这块我从第一次在 Django 项目里硬怼 API 开始就一直在用,陆陆续续踩了不少坑,也沉淀了一套自己比较顺手的设计流程。这篇文章就以“使用 Django Rest Framework 构建 API”为切入点,把从项…

2026/10/5 3:53:15 阅读更多 →
jQuery核心实践:选择器、第一个子元素与name获取全解析

jQuery核心实践:选择器、第一个子元素与name获取全解析

刚入门前端的时候纠结过一个问题:明明原生 JavaScript 写得好好的,为什么非要去学 jQuery?等到真正接手一个老项目,面对十几年前的代码库和一堆$符号满天飞的页面时,才明白这套东西到底有多普及。本文不谈玄虚概念&…

2026/10/5 3:53:15 阅读更多 →
吃豆人AI实战:Minimax、Alpha-Beta剪枝与Expectimax完整解析

吃豆人AI实战:Minimax、Alpha-Beta剪枝与Expectimax完整解析

如果你刷过伯克利CS61B,或者看过AI入门视频,大概率见过那只黄色吃豆人在迷宫里被鬼追得满地图跑的画面。那个场景十有八九就来自CS188的Project 2: Multi-Agents。这个项目是所有CS188课程作业里最有“游戏感”的一个,任务很直接——亲手写出…

2026/10/5 3:52:15 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →