我正在浏览我的一些代码,我意识到我实际上并不知道 CursorLoader 和 LoaderManager 组合如何与 CursorAdapter 连接一起使用。这是我感到困惑的部分。
1 2 3 4 5 6 7 8
| agendaAdapter = new MyAgendaAdapter(this, null);
makeProviderBundle(new String[] {"_id","event_name","start_date","start_time",
"end_date","end_time","location"},"date(?) >= start_date and date(?) <= end_date",
new String[]{getChosenDate(), getChosenDate()}, null);
getLoaderManager().initLoader(0, myBundle, MainDisplayActivity.this);
list.setAdapter(agendaAdapter); |
那么,我的自定义 ContentProvider 中的 query() 方法如何知道将其发送到特定的 CursorAdapter?我只是没有看到联系。我了解其中的所有其他内容,但这个问题是关于什么的。哦,我应该提一下,代码运行良好。
- 我开始怀疑你问这些问题只是为了和我开玩笑,我知道我忍不住回答(即使我在工作,哈哈)
-
idk 你在说什么:) 但如果你在那里......
首先,查看这篇文章和这篇文章中的代码示例,以更深入地了解该过程的工作原理。
现在,回答你的问题……
How does the query() method from my custom ContentProvider...?
嗯,首先要记住 getContentResolver().query() 不会直接调用内容提供者的 query 方法。您正在调用内容解析器的查询方法,该方法解析 Uri,确定您希望调用的提供程序,然后调用您的提供程序的 query 方法。
How does the query get sent to that specific CursorAdapter?
我将使用 API 演示作为示例来引导您完成整个过程。请注意,API 演示使用 ListFragment 而不是 ListActivity (区别在这个问题的上下文中并不重要)。
首先,创建(并设置)CursorAdapter.
1 2 3 4 5 6 7
| mAdapter = new SimpleCursorAdapter(
getActivity(),
android.R.layout.simple_list_item_2,
null,
new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
new int[] { android.R.id.text1, android.R.id.text2 },
0); |
在这个语句执行之后,SimpleCursorAdapter 知道它应该如何将游标数据与您的视图相关联。光标的 Contacts.DISPLAY_NAME 列中的任何数据都将与 ID 为 android.R.id.text1 的视图相关联,等等。
请注意,您已将 null 游标作为第三个参数传递给构造函数。这非常重要,因为我们还没有查询任何数据(这是 LoaderManager 和 CursorLoader 的工作)。
接下来,初始化加载器。
1
| getLoaderManager().initLoader(0, null, this); |
这告诉 LoaderManager 创建并启动对应于 id 0.
的 Loader
LoaderManager 调用 onCreateLoader(int id, Bundle args)。
onCreateloader 返回 Loader<Cursor> 接口的子类(即,在本例中为 CursorLoader)。此 CursorLoader 将执行初始查询,并在数据更改时自行更新。
如果您的活动/片段有多个加载器,那么您将使用 switch(id) 来确定已指示开始加载过程的特定加载器。
将查询到的游标传给onLoadFinished().
在 CursorLoader 被实例化并在步骤 3 中返回后,CursorLoader 立即在单独的线程上执行初始查询并返回一个游标。当 CursorLoader 完成查询时,它将新查询的游标返回给 LoaderManager,然后将游标传递给 onLoadFinished 方法。从文档中,"当先前创建的加载器完成加载时,将调用 onLoadFinished 方法。"
查询到的数据与CursorAdapter相关联。
1
| mAdapter.swapCursor(data); |
请注意,onLoadFinished 通常也是您使用查询数据更新活动/片段的 UI 的地方。在这种情况下,这不是必需的,因为我们之前称为 setListAdapter(mAdapter)。 ListFragment 知道如何使用 CursorAdapter(参见步骤 1)...我们需要做的就是将光标与 swapCursor 一起传递给适配器,而 ListFragment 将负责在我们的屏幕。
如果您有任何问题(或者是否有任何拼写错误等),请告诉我。
TL;博士
包含查询数据的游标与onLoadFinished中的CursorAdapter相关联。这通常通过调用 mAdapter.swapCursor(data).
来完成
- 装载机上的奇妙运行
-
不要感谢我...感谢 Android 市场上所有蹩脚、开发不佳的应用程序。这就是为什么我觉得有责任过度详细地解释这个过程的原因。 :)
-
嘿@AlexLockwood 快速提问。如果我将 CursorLoader 与 LoaderManager 一起使用,我无需担心关闭数据库或游标是否正确。但是当我像 getContentResolver().query() 一样直接使用它时呢?在那种情况下,我是否必须明确关闭它们,或者所有这些仍然由类本身处理?
-
如果您使用的是 CursorLoader LoaderManager,那么您不应该关闭 Cursor(否则可能会引发异常)。对所发生情况的极短但详细的解释是 Activity 告诉 LoaderManager 在 Activity 生命周期内执行某些操作(即,它将指示 LoaderManager 在配置更改时保留其 Loader )。 LoaderManager 将通过调用 CursorLoader 方法(即 onStartLoading、onStopLoading 以及从 Loader 类继承的一堆其他方法)来响应这些请求。
-
然后,在这些方法中,CursorLoader 将相应地关闭其光标(即在 onReset 等中)。换句话说,它不是 LoaderManager 关闭游标......它是 LoaderManager 告诉 CursorLoader 关闭游标。
-
但是,是的...基本上,当您使用 CursorLoaders 时,您永远不必关闭游标哈哈。但是,您应该关闭使用 getContentResolver().query 查询的游标,因为原始游标不受管理。
-
在 Activity/Fragment 生命周期中的哪个位置最好调用 getLoaderManager().initLoader?我查看了 Google 的源代码,他们到处都这样做:一些在 onCreate、onResume、onActivityCreated、onCreateView
-
@IgorGanapolsky 我记得在这里与其他一些 Android 开发人员讨论过这个问题。我总是在 onActivityCreated() 中初始化加载器。我同意你的观点,谷歌的文档对这一点有点含糊……但我从来没有遇到过在 onActivityCreated() 中初始化加载器的任何问题。
-
我想对自己的观点有更多的控制权。如何使用 CursorLoader 将 SimpleCursorAdapter 替换为 CursorAdapter?
-
我想为我(和其他所有人)澄清一些事情。在我用 oldCursor = cursorAdapter.swapCursor(newCursor) 交换光标后,我应该自己关闭 oldCursor 还是会得到照顾,或者这甚至是一个坏主意?我知道 newCursor 在任何情况下都不应该关闭,至少直到它没有被换成新的。