CursorLoader与LoaderManager如何知道将游标发送给CursorAdapter?

22

我正在查看我的一些代码,发现我实际上不知道如何使用将 CursorLoaderLoaderManagerCursorAdapter 结合起来。下面是我困惑的部分。

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的呢?我就是不明白这个连接。除了这个问题,我对其中的一切都理解。哦,我应该提一下,代码可以正常工作。


1
我开始怀疑你是在故意问这些问题来捉弄我,知道我不能不回答(即使我在工作中哈哈) - Alex Lockwood
我不知道你在说什么 :) 但如果你在那里... - Andy
1个回答

84

首先,请查看这篇文章这篇文章中的代码示例以深入了解该过程。

现在,回答您的问题...

我的自定义ContentProvider中的query()方法是如何工作的?

首先要记住的是,getContentResolver().query()不会直接调用内容提供程序的query方法。您正在调用内容解析器的查询方法,该方法会解析Uri,确定要调用的提供程序,然后再调用您的提供程序的query方法

查询是如何发送到特定的CursorAdapter的?

我将使用API演示作为示例,向您介绍此过程。请注意,API演示使用的是ListFragment而不是ListActivity(在此问题的背景下,这种区别并不重要)。


  1. 首先,创建(并设置)CursorAdapter

  2. 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游标作为构造函数的第三个参数传递。这非常重要,因为我们尚未查询任何数据(这是LoaderManagerCursorLoader的工作)。

  3. 接下来,初始化加载器。

  4. getLoaderManager().initLoader(0, null, this);
    
    这将告诉LoaderManager创建并启动与ID 0对应的Loader

  5. LoaderManager调用onCreateLoader(int id, Bundle args)

    onCreateLoader返回Loader<Cursor>接口的子类(在本例中为CursorLoader)。这个CursorLoader将执行初始查询,并在数据发生更改时更新自身。

    如果活动/片段有多个加载器,则可以使用switch(id)来确定具体指示开始加载过程的加载器。

  6. 查询的游标传递给onLoadFinished()

    在步骤3中立即实例化并返回CursorLoader后,CursorLoader在单独的线程上执行初始查询,并返回一个游标。当CursorLoader完成查询时,它将新查询的游标返回给LoaderManager,后者将游标传递给onLoadFinished方法。根据文档,“在先前创建的加载器完成其加载时调用onLoadFinished方法。”

  7. 查询的数据与CursorAdapter关联。

    mAdapter.swapCursor(data);
    
    请注意,通常在onLoadFinished函数中更新活动/片段的UI以显示已查询的数据。但在这种情况下,这并不是必要的,因为我们之前已经调用了setListAdapter(mAdapter)。ListFragment知道如何使用CursorAdapter(参见步骤1)...我们只需要使用swapCursor将适配器与光标关联起来,ListFragment会负责将数据显示在屏幕上。
    如果您有任何问题(或者有任何错别字等),请告诉我。
    简而言之,在onLoadFinished函数中,将包含查询数据的光标与CursorAdapter相关联。通常可以通过调用mAdapter.swapCursor(data)实现。

2
装载器方面的精彩介绍。 - SeanPONeil
13
不要感谢我...要感谢所有糟糕、开发不良的Android应用程序。正是因为它们,我才觉得有责任详细地解释这个过程,甚至偏执地解释。 :) - Alex Lockwood
1
嘿 @AlexLockwood,有个小问题。如果我正在使用具有LoaderManager的CursorLoader,则不需要担心关闭数据库或游标,对吧?但是如果我直接像这样使用getContentResolver().query(),那该怎么办呢?在这种情况下,我是否必须显式地关闭它们,还是所有这些仍由类本身处理呢? - Andy
2
然后,在这些方法中,CursorLoader将相应地关闭其游标(即在onReset等方法中)。换句话说,不是LoaderManager关闭游标...而是LoaderManager告诉CursorLoader关闭游标。 - Alex Lockwood
1
@IgorGanapolsky 我记得曾经和其他一些Android开发人员在这里讨论过这个问题(https://twitter.com/cyrilmottier/status/372646529255092224)。我总是在`onActivityCreated()`中初始化加载器。我同意你的观点,即Google的文档在这一点上有点模糊......但我从未在`onActivityCreated()`中初始化加载器遇到任何问题。 - Alex Lockwood
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接