news 2026/9/29 2:40:30

Android 中的 adapter 和作用以及常见的 adapter:从 BaseAdapter 到 FragmentPagerAdapter 的配置骨架

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android 中的 adapter 和作用以及常见的 adapter:从 BaseAdapter 到 FragmentPagerAdapter 的配置骨架

1. 列表渲染为什么总卡在 Adapter 这一层

Android 里的 adapter 说白了就是数据与 UI 之间的桥梁,它把后台数据与前端界面连接到一起,是一个展示数据的载体。你写一个 ListView、GridView、Spinner 或者 ViewPager,真正决定「每一行长什么样、有几行、数据变了怎么刷新」的,不是控件本身,而是你塞进去的那个 Adapter。很多人第一次接触 Android 列表开发,卡住的地方往往不是布局写不出来,而是搞不清 BaseAdapter、ArrayAdapter、FragmentPagerAdapter 各自该在什么场景用,职责边界在哪。

这篇就聚焦 Android 列表与分页这两个高频场景,把常见 Adapter 的选型思路和可复制的骨架代码梳理一遍。适合已经能写 Activity、但对 Adapter 体系还是一团浆糊的开发者。我会先讲清楚每个 Adapter 的定位,再给出能直接跑的配置骨架,最后说明在 Cline 的 settings.json 里接入 TaoToken 统一 Key/API 通道的验证动作,目标是一次跑通列表渲染与分页切换。整个过程不需要你额外折腾网络环境,按步骤配就行。

2. 常见 Adapter 的职责边界与选型

2.1 BaseAdapter:通用但抽象,适合自定义列表

BaseAdapter 是基础适配器,对 Spinner、ListView、GridView 都是通用的。它是一个抽象类,继承之后要实现的方法比较多,典型的有 getCount、getItem、getItemId、getView 这几个。它的好处是控制力最强,你想怎么绑定数据、怎么复用 convertView、怎么做 ViewHolder 优化,全都自己说了算。缺点是模板代码多,简单列表用它属于杀鸡用牛刀。

我一般这样判断:如果列表项布局复杂、需要多种 item 类型、或者要做精细的视图复用,就选 BaseAdapter;如果只是展示一串字符串,用 ArrayAdapter 更省事。

2.2 ArrayAdapter:泛型直给,简单列表首选

ArrayAdapter 是 BaseAdapter 的一个子类,可以直接使用泛型,使用起来比较简单。你给它一个 Context、一个 item 布局、一个 List,它就能把数据渲染出来。对于纯文本列表,一行代码就能搞定,不需要自己写 getView。

它的边界也很清楚:item 布局基本固定,数据是单一类型。一旦你要在每行里塞图片、按钮、多状态切换,ArrayAdapter 就会变得别扭,这时候退回 BaseAdapter 更合适。

2.3 Cursor 系列:从数据库直接喂给列表

CursorAdapter、SimpleCursorAdapter、ResourceCursorAdapter 这一族,核心是把数据库查询返回的 Cursor 直接映射到列表上。SimpleCursorAdapter 可以从数据库中读取数据显示在列表上,典型用法是这样:

ContentResolver contentResolver = getContentResolver(); Cursor query = contentResolver.query( Contacts.People.CONTENT_URI, null, null, null, null); // 将 query 交给 Activity 管理,使其与 Activity 生命周期同步 startManagingCursor(query); SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter( this, android.R.layout.simple_expandable_list_item_1, query, new String[]{Contacts.People.NAME}, new int[]{android.R.id.text1});

这里 from 数组是 Cursor 里的列名,to 数组是布局里的控件 id,两者一一对应。注意 startManagingCursor 在新版本里已经废弃,实际项目建议用 Loader 或 Room 配合观察者模式,但理解这个映射关系对看懂老代码很有帮助。

2.4 SimpleAdapter:HashMap 驱动的灵活布局

SimpleAdapter 扩展性好,可以定义各种各样的布局,它里面涉及到的数据全是 HashMap 构成的 List。每一行是一个 Map,key 是列名,value 是具体内容,再通过 from/to 数组做映射。它比 ArrayAdapter 灵活,又比 BaseAdapter 省事,适合中等复杂度的列表。

2.5 FragmentPagerAdapter:分页场景的主力

FragmentPagerAdapter 是 PagerAdapter 中的一种实现,它继承自 PagerAdapter。它将每一个页面表示为一个 Fragment,并且每一个 Fragment 都将会保存到 FragmentManager 当中。只有当用户没可能再次回到页面的时候,FragmentManager 才会将这个 Fragment 销毁。这个特性决定了它适合页数固定、每页内容较重的场景,比如「我的患者」这种多标签分页。

3. 可复制的 Adapter 骨架代码

3.1 BaseAdapter 骨架(带 ViewHolder)

public class PatientAdapter extends BaseAdapter { private final Context context; private final List<Patient> data; public PatientAdapter(Context context, List<Patient> data) { this.context = context; this.data = data; } @Override public int getCount() { return data.size(); } @Override public Object getItem(int position) { return data.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 = LayoutInflater.from(context) .inflate(R.layout.item_patient, parent, false); holder = new ViewHolder(); holder.name = convertView.findViewById(R.id.tv_name); holder.age = convertView.findViewById(R.id.tv_age); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } Patient p = data.get(position); holder.name.setText(p.getName()); holder.age.setText(String.valueOf(p.getAge())); return convertView; } static class ViewHolder { TextView name; TextView age; } }

关键点在于 convertView 复用和 ViewHolder 缓存,少了这两样,长列表滑动会明显掉帧。

3.2 ArrayAdapter 骨架

ArrayAdapter<String> adapter = new ArrayAdapter<>( this, android.R.layout.simple_list_item_1, nameList); listView.setAdapter(adapter);

数据变化时调用adapter.notifyDataSetChanged()即可刷新。

3.3 FragmentPagerAdapter 骨架

mViewPager = view.findViewById(R.id.vp_show_myadd_patient); mShowMyPatientListAdapter = new ShowMyPatientListAdapter( getActivity().getSupportFragmentManager()); mViewPager.setAdapter(mShowMyPatientListAdapter); class ShowMyPatientListAdapter extends FragmentPagerAdapter { public ShowMyPatientListAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mArrayList.get(position); } @Override public int getCount() { return mArrayList.size(); } }

这里 mArrayList 是保存 Fragment 的集合,直接传入即可。getItem 按位置返回对应 Fragment,getCount 决定页数。

3.4 数据刷新与分页切换配置

列表数据更新后,主线程调用 notifyDataSetChanged。分页切换则依赖 ViewPager 的滑动或setCurrentItem(index)。如果你用 TabLayout 联动,记得把 ViewPager 传给 TabLayout 的 setupWithViewPager。分页数据懒加载可以在 Fragment 的 onResume 里判断是否首次加载,避免每次切回都重新请求。

4. 在 Cline 中接入 TaoToken 并验证请求

4.1 配置 settings.json

打开 Cline 的 settings.json,把模型请求统一走 TaoToken 的 API 通道。API 地址是https://taotoken.net/api,Key 从控制台生成。配置片段如下:

{ "cline.apiProvider": "openai", "cline.openAiBaseUrl": "https://taotoken.net/api", "cline.openAiApiKey": "你的_TaoToken_Key", "cline.openAiModelId": "claude-sonnet-4-20250514" }

Key 的获取入口在控制台的 API Keys 页面,生成后复制粘贴即可。接入文档里有各语言 SDK 的调用示例,遇到字段对不上可以对照排查。

4.2 验证请求是否跑通

配置保存后,在 Cline 里发一条最简单的请求,比如让它解释一段 BaseAdapter 代码。如果返回正常,说明 Key 和通道都通了。你也可以用 curl 直接验证:

curl https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer 你的_TaoToken_Key" \ -d '{ "model": "claude-sonnet-4-20250514", "messages": [{"role": "user", "content": "用一句话说明 BaseAdapter 的作用"}] }'

返回里有 choices 字段且内容合理,就代表链路正常。这一步跑通后,列表渲染和分页切换的调试就能借助模型辅助,效率会高不少。

5. 本篇常见错误排查

5.1 notifyDataSetChanged 不生效

最常见的原因是数据引用没变。如果你重新赋值了一个新 List 给 adapter,但 adapter 内部持有的还是旧引用,刷新就不会生效。正确做法是清空原 List 再 addAll,或者让 adapter 持有可变集合。

5.2 FragmentPagerAdapter 页数不对

getCount 返回 0 或者集合为 null,ViewPager 就什么都不显示。检查 mArrayList 是否在 setAdapter 之前已经填充完毕。另外 FragmentManager 要用 getSupportFragmentManager,用错会直接崩。

5.3 getView 里重复 inflate 导致卡顿

没有判断 convertView == null 就每次都 inflate,长列表滑动会非常卡。务必加上复用判断和 ViewHolder。

5.4 Cursor 关闭时机

Cursor 用完不关会泄漏。老代码用 startManagingCursor 让 Activity 托管,新代码建议在 onDestroy 或 Loader 回调里手动 close。

5.5 API 请求 401

多半是 Key 没填对或者 BaseUrl 少了 /api。检查 settings.json 里的地址是否为https://taotoken.net/api,Key 是否有多余空格。

6. 选型与接入的收尾建议

列表场景优先 ArrayAdapter,复杂 item 上 BaseAdapter,数据库直出用 Cursor 系列,分页固定页数用 FragmentPagerAdapter。接入方面,排障和接入细节可以对照 API Keys 和接入文档;想先验证模型效果,直接去模型对话试几条;如果是长期编码或 Agent 场景,Coding Plan 会更划算。把 settings.json 配好、curl 验证通过,列表渲染和分页切换这条链路基本就稳了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 2:38:43

Bootstrap Icons 的 cloud-arrow-up 图标:源码解析与五种实际用法

前端 【免费下载链接】icons Official open source SVG icon library for Bootstrap. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ic/icons 点击查看 免费下载 本指南围绕 Bootstrap Icons 官方开源 SVG 图标库中的 cloud-arrow-up 图标展开&#xff0c;结合仓库内…

作者头像 李华
网站建设 2026/9/29 2:38:10

trackerslist:BT 公共 Tracker 列表完整使用指南

trackerslist&#xff1a;BT 公共 Tracker 列表完整使用指南 【免费下载链接】trackerslist Updated list of public BitTorrent trackers 项目地址: https://gitcode.com/GitHub_Trending/tr/trackerslist trackerslist 是一个每天自动更新的 BitTorrent 公共 Tracker …

作者头像 李华
网站建设 2026/9/29 2:35:22

Keil环境下单片机串口printf打印中文乱码解决全攻略

1. 串口打印中文这件事&#xff0c;为什么值得单独拎出来讲搞过单片机的人都有一个共同习惯&#xff1a;调试阶段第一件事就是把串口打通&#xff0c;然后用printf往电脑上怼信息。打印英文和数字从来不是问题&#xff0c;一行printf("Hello\r\n")就能跑起来。可一旦…

作者头像 李华
网站建设 2026/9/29 2:35:08

模拟器真机参数改造防检测:从ARM指令集到电池传感器

在安卓开发和测试圈里&#xff0c;模拟器一直是个又爱又恨的东西。爱它开箱即用、多开方便&#xff0c;恨它一进应用就被识别出来&#xff0c;要么直接闪退&#xff0c;要么功能被限制。尤其是这两年&#xff0c;各类App对运行环境的校验越来越狠&#xff0c;银行类、社交类、游…

作者头像 李华
网站建设 2026/9/29 2:32:26

LVS三种模式实战:NAT、DR、TUN原理与配置全解析

搞负载均衡的兄弟们应该都听过LVS这三个字母&#xff0c;Linux Virtual Server&#xff0c;从当年章文嵩博士的开源项目一直活到今天&#xff0c;内核里自带IPVS模块&#xff0c;稳得一批。这么多年过去了&#xff0c;Nginx、HAProxy轮番上场&#xff0c;但LVS依然在不少核心链…

作者头像 李华
网站建设 2026/9/29 2:31:56

大模型数字化运营落地指南:场景拆解、成本测算与避坑实践

简介&#xff1a;这份PPTX演示文稿聚焦大模型与数字化运营的结合&#xff0c;系统性介绍深度神经网络架构、海量参数训练与计算资源需求等技术原理&#xff0c;并从自然语言处理、计算机视觉、语音交互到推荐系统等典型场景展开应用分析。针对数字化运营现状&#xff0c;梳理数…

作者头像 李华