我有一个 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了。
然而,这应该由
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
代码过于臃肿。