首页/新闻资讯/正文详情

contact 基础知识总结与类图:Fragment 中 LoaderManager 与 CursorLoader 配置骨架

发布时间:2026/9/23 13:22:52 来源:云帆数科 栏目:资讯中心
contact 基础知识总结与类图:Fragment 中 LoaderManager 与 CursorLoader 配置骨架
1. 从一次联系人列表卡顿说起Android 联系人模块里Fragment、LoaderManager、AsyncLoader、CursorLoader这几个类经常一起出现但真正落到代码里很多人会卡在“到底谁初始化谁、回调为什么不触发、类图怎么画才不绕”。这篇就聚焦 Android 联系人模块的基础骨架在Fragment里用LoaderManager驱动AsyncLoader/CursorLoader读取联系人并给出可复制的初始化代码、CursorLoader参数配置以及一张能看懂的类图字段与关系标注。如果你正在做MultiSelectContactsListFragment、AllContactsFragment、SmartDialSearchFragment、RegularSearchFragment这类界面或者只是想把getLoaderManager().initLoader()的调用链理顺这篇可以直接跟着敲。核心检索词先摆出来Fragment中通过LoaderManager管理AsyncLoaderCursorLoader负责在后台线程查询ContactsContract查询结果通过onLoadFinished回到主线程刷新列表。适合已经会写RecyclerView、但对 Loader 三件套回调顺序模糊的 Android 开发者。我试过在联系人搜索页里把 Loader 初始化放在onCreateView和onActivityCreated两个位置结果回调触发时机完全不同后面会把这个坑单独拆开讲。2. TaoToken 前置把模型对话和接入文档放在手边写这类系统模块代码时我习惯把 API 文档和模型对话窗口开着遇到ContactsContract字段记不清、或者CursorLoader构造参数顺序拿不准直接问比翻源码快。TaoToken 这边可以这样用模型对话入口用来快速确认ContactsContract.CommonDataKinds.Phone.CONTENT_URI这类常量的完整路径以及LoaderManager在不同 API Level 下的行为差异。接入文档里能查到 API Key 的生成方式和请求示例方便你在本地写一个最小验证脚本确认查询条件拼得对不对。模型对话https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewriteAPI Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite如果你后面要长期做 Android 编码或 Agent 类工具链可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite注意TaoToken 是模型调用与文档查询的辅助入口不替代 Android Studio 和真机调试。Loader 回调是否触发最终还是要看 Logcat。3. 可复制配置LoaderManager 初始化与 CursorLoader 参数骨架3.1 Fragment 中初始化 LoaderManager三要素关系先理清Fragment或Activity持有LoaderManagerLoaderManager管理一个或多个LoaderAsyncLoader是抽象基类CursorLoader是它的子类。初始化入口就一行getLoaderManager().initLoader(LOADER_ID, null, this);这里LOADER_ID是自定义常量this要求当前Fragment实现LoaderManager.LoaderCallbacksCursor。完整骨架如下public class ContactsListFragment extends Fragment implements LoaderManager.LoaderCallbacksCursor { private static final int LOADER_ID_CONTACTS 1001; private RecyclerView recyclerView; private ContactsAdapter adapter; Override public void onActivityCreated(Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // 在视图创建完成后初始化避免回调早于 RecyclerView 就绪 getLoaderManager().initLoader(LOADER_ID_CONTACTS, null, this); } NonNull Override public LoaderCursor onCreateLoader(int id, Nullable Bundle args) { if (id ! LOADER_ID_CONTACTS) { throw new IllegalArgumentException(unknown loader id: id); } String[] projection new String[]{ ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER }; String selection ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME IS NOT NULL; String sortOrder ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME ASC; return new CursorLoader( requireContext(), ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, selection, null, sortOrder ); } Override public void onLoadFinished(NonNull LoaderCursor loader, Cursor data) { if (loader.getId() LOADER_ID_CONTACTS) { adapter.swapCursor(data); } } Override public void onLoaderReset(NonNull LoaderCursor loader) { if (loader.getId() LOADER_ID_CONTACTS) { adapter.swapCursor(null); } } }CursorLoader构造参数顺序是Context、Uri、projection、selection、selectionArgs、sortOrder。这六个参数里最容易写错的是selectionArgs如果selection里用了?占位符selectionArgs必须按顺序传值否则查询会返回空游标。3.2 AsyncLoader 子类需要覆写的方法CursorLoader本身已经实现了完整功能但如果你要自定义AsyncLoader子类必须覆写这几个方法才能形成闭环public class CustomAsyncLoader extends AsyncLoaderCursor { Override public Cursor loadInBackground() { // 后台线程执行不能碰 UI return queryContacts(); } Override protected void onStartLoading() { forceLoad(); // 触发 loadInBackground } Override protected void onStopLoading() { cancelLoad(); } Override protected void onReset() { super.onReset(); onStopLoading(); } Override public void onCanceled(Cursor data) { if (data ! null !data.isClosed()) { data.close(); } } Override protected void deliverResult(Cursor data) { if (isReset()) { if (data ! null) data.close(); return; } super.deliverResult(data); } }loadInBackground()是必须实现的抽象方法其余几个方法决定 Loader 的生命周期行为。onStartLoading()里调forceLoad()是最常见的触发方式不调的话loadInBackground()不会执行。3.3 类图字段与关系标注类图不用画得太复杂抓住继承和持有关系即可类类型关键字段/方法关系Fragment界面类getLoaderManager()持有 LoaderManagerLoaderManager管理类initLoader()、destroyLoader()管理多个 LoaderLoaderCallbacks接口onCreateLoader、onLoadFinished、onLoaderReset由 Fragment 实现AsyncLoader抽象类loadInBackground()、deliverResult()继承 LoaderCursorLoader具体类构造参数六元组继承 AsyncLoaderContactsContract数据契约CONTENT_URI、DISPLAY_NAME被 CursorLoader 查询关系标注Fragment实现LoaderCallbacksLoaderManager回调FragmentCursorLoader继承AsyncLoaderAsyncLoader继承Loader。画图时把LoaderManager放在中间左边连Fragment右边连Loader家族继承线用空心三角持有线用实心菱形。4. 验证请求确认查询回调是否触发代码写完怎么确认onCreateLoader和onLoadFinished真的被调用了按下面步骤操作第一步在三个回调里各加一行日志Override public LoaderCursor onCreateLoader(int id, Bundle args) { Log.d(LoaderTrace, onCreateLoader id id); // ... 构造 CursorLoader } Override public void onLoadFinished(LoaderCursor loader, Cursor data) { Log.d(LoaderTrace, onLoadFinished count (data null ? -1 : data.getCount())); adapter.swapCursor(data); } Override public void onLoaderReset(LoaderCursor loader) { Log.d(LoaderTrace, onLoaderReset); adapter.swapCursor(null); }第二步运行 App进入联系人列表页过滤 Logcatadb logcat -s LoaderTrace预期输出顺序是onCreateLoader id1001随后onLoadFinished countN。如果只看到onCreateLoader没有onLoadFinished说明loadInBackground()没执行或查询抛异常。第三步验证数据变化时回调是否重新触发。在联系人 App 里新增一个联系人回到你的页面观察onLoadFinished是否再次打印且count增加。CursorLoader会监听CONTENT_URI的变化数据变动时自动重新查询。第四步验证onLoaderReset。调用getLoaderManager().destroyLoader(LOADER_ID_CONTACTS)日志应出现onLoaderReset此时适配器里的游标应被置空避免使用已关闭的 Cursor。5. 本篇常见错排查5.1 回调不触发initLoader 调用时机太早如果在onCreate()里调initLoader()此时RecyclerView还没创建onLoadFinished可能先于视图初始化执行导致adapter为 null。放到onActivityCreated()或onViewCreated()里更稳。5.2 Cursor 已关闭onLoadFinished 里做了异步操作onLoadFinished返回的Cursor由 Loader 管理一旦onLoaderReset触发就会被关闭。如果你在onLoadFinished里开子线程延迟读取 Cursor很容易遇到StaleDataException。正确做法是在回调里同步把数据交给适配器或者拷贝出需要的数据。5.3 查询返回空selection 和 selectionArgs 不匹配// 错误写法selection 有 ? 但 selectionArgs 传 null new CursorLoader(ctx, uri, projection, Phone.DISPLAY_NAME ?, null, sortOrder); // 正确写法 new CursorLoader(ctx, uri, projection, Phone.DISPLAY_NAME ?, new String[]{张三}, sortOrder);5.4 权限问题READ_CONTACTS 未授权Android 6.0 以上需要运行时申请READ_CONTACTS。没授权时CursorLoader查询会返回空游标或抛SecurityException但日志里不一定明显。先在onLoadFinished里打印data.getCount()如果是 0 且确认有联系人优先检查权限。uses-permission android:nameandroid.permission.READ_CONTACTS /5.5 Loader ID 冲突多个 Loader 共用同一 ID一个 Fragment 里如果有多个查询比如全部联系人和搜索联系人必须用不同LOADER_ID。initLoader相同 ID 会复用已有 Loader不会重新创建导致onCreateLoader不执行。6. 接入与排障入口Loader 回调链路排查清楚后如果你想把联系人查询逻辑接到模型辅助的编码流程里可以从 API Keys 和接入文档开始API Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite模型对话https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite长期做 Android 编码或 Agent 工具链的话Coding Plan 入口在这里https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite最后留一个实用技巧类图画完后把Fragment、LoaderManager、AsyncLoader、CursorLoader四个类的关键方法各写一行注释贴在代码旁边比反复翻图快。回调顺序记不住的时候直接在onCreateLoader、onLoadFinished、onLoaderReset三处打日志跑一遍比看任何文档都直观。

相关推荐

QM77031数据手册阅读指南:从引脚表到应用电路的关键要点
QM77031数据手册阅读指南:从引脚表到应用电路的关键要点

简介:这是一份 Qorvo 公司 QM77031 线性多模式中高频 S-PAD 模块的官方数据手册,面向移动通信射频前端设计、硬件选型与调试人员。QM77031 内部集成三条 3G/4G 中高频放大器路径以及滤波器、双工器、四工器和天线开关,支持 WCDMA/CDMA2000/FD… · 2026/9/23 13:22:52

2026最新天津市属于哪个省面试突击:3个考点避坑指南
2026最新天津市属于哪个省面试突击:3个考点避坑指南

2026最新天津市属于哪个省面试突击:3个考点避坑指南 官方文档翻烂了还是记不住重点?别慌,这不是你的问题。2026年的技术面试,早就不是死记硬背“天津市属于哪个省”这种常识题那么简单了。很多资深工程师在二面甚至三面时,都会被问倒——不是问… · 2026/9/23 13:22:52

CNG加气站设计与建设关键技术解析
CNG加气站设计与建设关键技术解析

1. CNG加气站行业背景与需求分析压缩天然气(CNG)作为清洁能源在交通领域的应用已有30余年历史。根据行业数据显示,全球CNG车辆保有量年均增长率保持在8%以上,这种增长直接带动了加气站建设需求的持续攀升。与传统加油站相比&#… · 2026/9/23 13:22:52

Captura 命令行 `list` 命令完全指南:一次枚举编码器、屏幕、窗口与音频设备
Captura 命令行 `list` 命令完全指南:一次枚举编码器、屏幕、窗口与音频设备

Captura 命令行 list 命令完全指南:一次枚举编码器、屏幕、窗口与音频设备 【免费下载链接】Captura Capture Screen, Audio, Cursor, Mouse Clicks and Keystrokes 项目地址: https://gitcode.com/gh_mirrors/ca/Captura captura list 是 Captura 命令行工具… · 2026/9/23 14:08:16

UNet、R2UNet、Attention-UNet 选哪个?PyTorch 实战对比与避坑指南
UNet、R2UNet、Attention-UNet 选哪个?PyTorch 实战对比与避坑指南

简介:这份资源面向计算机视觉方向的学习者与研究者,聚焦图像分割这一核心任务,提供基于Pytorch实现的UNet、R2UNet、Attention-UNet与AttentionR2UNet四种经典网络结构的完整项目实战代码。内容覆盖医学影像分析、自动驾驶、视频监控等典型应… · 2026/9/23 14:08:16

PHPStan 错误标识 `parameter.internalClass` 深度解析:函数/方法参数类型声明引用了内部类
PHPStan 错误标识 `parameter.internalClass` 深度解析:函数/方法参数类型声明引用了内部类

开发工具代码质量静态分析 【免费下载链接】phpstan PHP Static Analysis Tool - discover bugs in your code without running it! 项目地址: https://gitcode.com/gh_mirrors/ph/phpstan 点击查看 免费下载 PHPStan 的 parameter.internalClass 错误标识&#xf… · 2026/9/23 14:08:16

移动流量包性能优化:3招解决版本升级API全变痛点
移动流量包性能优化:3招解决版本升级API全变痛点

移动流量包性能优化:3招解决版本升级API全变痛点 刚把项目里的移动流量包SDK升到最新版,直接懵了。 旧版的 fetchData 方法没了, onSuccess 回调变成了Promise,连参数名都改了。 这种 版本升级后 API… · 2026/9/23 14:08:09

别再死记硬背了 2026最新HTML底层解析指南
别再死记硬背了 2026最新HTML底层解析指南

别再死记硬背了 2026最新HTML底层解析指南 你是不是也遇到过这种尴尬:CSS写了一堆,JS逻辑跑通了,但一上浏览器,页面就变成一锅粥。明明每一个标签都背得滚瓜烂熟, div 、 span 、 p… · 2026/9/23 14:08:09

3招搞定vue刷新当前页面2026最新性能优化实战
3招搞定vue刷新当前页面2026最新性能优化实战

3招搞定vue刷新当前页面2026最新性能优化实战 配置环境就卡半天?别急着骂娘。很多转行前端的朋友,刚搭好 Vue 项目,想通过刷新页面重置状态,结果发现浏览器控制台一堆红字,页面卡顿得让人想摔键盘。这不仅仅是配置问题,更是性能陷阱。今天… · 2026/9/23 14:08:09

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码