尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

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

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 SimpleAdapterHashMap 驱动的灵活布局SimpleAdapter 扩展性好可以定义各种各样的布局它里面涉及到的数据全是 HashMap 构成的 List。每一行是一个 Mapkey 是列名value 是具体内容再通过 from/to 数组做映射。它比 ArrayAdapter 灵活又比 BaseAdapter 省事适合中等复杂度的列表。2.5 FragmentPagerAdapter分页场景的主力FragmentPagerAdapter 是 PagerAdapter 中的一种实现它继承自 PagerAdapter。它将每一个页面表示为一个 Fragment并且每一个 Fragment 都将会保存到 FragmentManager 当中。只有当用户没可能再次回到页面的时候FragmentManager 才会将这个 Fragment 销毁。这个特性决定了它适合页数固定、每页内容较重的场景比如「我的患者」这种多标签分页。3. 可复制的 Adapter 骨架代码3.1 BaseAdapter 骨架带 ViewHolderpublic class PatientAdapter extends BaseAdapter { private final Context context; private final ListPatient data; public PatientAdapter(Context context, ListPatient 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 骨架ArrayAdapterString 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 按位置返回对应 FragmentgetCount 决定页数。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/apiKey 从控制台生成。配置片段如下{ 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 或者集合为 nullViewPager 就什么都不显示。检查 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/apiKey 是否有多余空格。6. 选型与接入的收尾建议列表场景优先 ArrayAdapter复杂 item 上 BaseAdapter数据库直出用 Cursor 系列分页固定页数用 FragmentPagerAdapter。接入方面排障和接入细节可以对照 API Keys 和接入文档想先验证模型效果直接去模型对话试几条如果是长期编码或 Agent 场景Coding Plan 会更划算。把 settings.json 配好、curl 验证通过列表渲染和分页切换这条链路基本就稳了。
返回列表