CursorLoader如果在注册ContentObserver之前调用notifyChange(),则不会刷新。

3
我有一个 CursorLoader,从本地 SQLite 数据库加载数据。
SQLite 中的数据实际上是远程 API 响应的缓存副本,因此每当 CursorLoader 查询时,我都会异步刷新 SQLite 数据。
以下是我在 ContentProvider 中响应数据查询的步骤序列:
1. 查询缓存数据的 SQLite。返回的游标上调用 cursor.setNotificationUri(getContext().getContentResolver(), uri)。
2. 开始异步调用远程 API。一旦收到响应,就会调用 getContext().getContentResolver().notifyChange(uri, null)。
3. 等待 5 秒钟,以延迟 CursorLoader 接收游标。(这样做是为了更容易地重现我的问题)。
4. 将在第 1 步中获得的游标返回给 CursorLoader。
在异步远程API调用完成(并调用notifyChange())之前,如果CursorLoader无法通过调用registerContentObserver(cursor, mObserver)注册获取到的游标上的ContentObserver [参见http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/content/CursorLoader.java#CursorLoader.loadInBackground%28%29],则数据更改通知将被CursorLoader忽略,因此Activity看不到更新的数据。为了解决这个问题,我可以编写我的LoaderCallBacks,使得数据加载两次——首先仅加载缓存数据,然后进行刷新请求。这样,CursorLoader就有机会在刷新调用开始之前注册ContentObserver了。
然而,这应该由CursorLoader本身处理,因为CursorLoader宣传自动更新游标。在每个Activity中这样做会导致Activity代码过于臃肿。

@diosney 感谢您的格式化!将来会记住这个。 - Vijay Aggarwal
1
不用谢!我们在这里互相帮助 :) - Diosney
2个回答

1

我的方法是在开始加载光标之前注册观察者。您需要为Uri注册,而不是为光标注册。

 getActivity().getContentResolver().registerContentObserver(
 your_Uri, true,
 new YourObserver(mHandler));

getLoaderManager().initLoader(0, null, this);

从文档中看来,CursorLoader 已经在刷新内容,你不需要使用 ContentObserver。实际上,我无法使其在更改时自动刷新,但是我会在解决此问题后立即更新它。 - StErMi
使用CursorLoader时,您无需添加ContentObserver。您只需要在ContentProvider的查询方法中添加以下内容,就在返回游标之前:cursor.setNotificationUri(getContext().getContentResolver(), uri)。这样就可以解决问题了。 - StErMi
@StErMi - 如果您正在加载“派生”的URI,例如视图,则需要添加另一个ContentObserver,以便在基础表之一(具有自己的Uri)更改时通知支持视图的游标。 - zyamys
1
@zyamys ContentProvider的工作是告诉解析器应该通知哪些URI。如果ContentProvider被正确实现,就不应该出现所描述的情况。 - Pijusn
@Pius - 很好的观点,假设您对提供程序有控制权,那是更好的解决方案。 - zyamys

0
在初始化时,可以通过以下方式获取您的加载器的引用:

get a reference to your loader while initializing as follows

Loader dayWeatherLoader = getLoaderManager().initLoader(LOADER_DAY_WEATHER, null, this);

然后创建一个继承ContentObserver的类,如下所示

class DataObserver extends ContentObserver {

public DataObserver(Handler handler) {
    super(handler);
}

@Override
public void onChange(boolean selfChange, Uri uri) {
    dayWeatherLoader.forceLoad();
}
}

然后在onResume生命周期方法中注册内容观察器,如下所示

@Override
public void onResume() {
super.onResume();
getContext().getContentResolver().registerContentObserver(CONTENTPROVIDERURI,true,new DayWeatherDataObserver(new Handler()));
}

无论何时内容提供程序的基础数据发生变化,contentobserver 的 onChange 方法都会被调用,在这里您可以要求加载器重新加载数据。

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