【发布时间】:2017-06-06 12:29:28
【问题描述】:
为了从数据库中获取数据,我在应用程序中使用了CursorLoader。一旦onLoadFinished()回调方法调用应用程序的逻辑将Cursor对象转换为业务模型要求内的List对象。如果有大量数据,这种转换(繁重的操作)需要一些时间。这会减慢 UI 线程。我尝试使用RxJava2 传递Cursor 对象在非UI Thread 中开始转换,但得到Exception:
Caused by: android.database.StaleDataException: Attempting to access a closed CursorWindow.Most probable cause: cursor is deactivated prior to calling this method.
这是Fragment的部分代码:
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
QueryBuilder builder;
switch (id) {
case Constants.FIELDS_QUERY_TOKEN:
builder = QueryBuilderFacade.getFieldsQB(activity);
return new QueryCursorLoader(activity, builder);
default:
return null;
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (cursor.getCount() > 0) {
getFieldsObservable(cursor)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::showFields);
} else {
showNoData();
}
}
private static Observable<List<Field>> getFieldsObservable(Cursor cursor) {
return Observable.defer(() -> Observable.just(getFields(cursor))); <-- Exception raised at this line
}
private static List<Field> getFields(Cursor cursor) {
List<Field> farmList = CursorUtil.cursorToList(cursor, Field.class);
CursorUtil.closeSafely(cursor);
return farmList;
}
这里使用CursorLoader 的目的是在数据存储更新时从数据库获取通知。
更新
正如 Tin Tran 所建议的,我删除了 CursorUtil.closeSafely(cursor);,现在我得到了另一个例外:
Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: /data/user/0/com.my.project/databases/db_file
at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
at android.database.CursorWindow.getNumRows(CursorWindow.java:225)
at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:121)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:236)
at android.database.AbstractCursor.moveToNext(AbstractCursor.java:274)
at android.database.CursorWrapper.moveToNext(CursorWrapper.java:202)
at com.db.util.CursorUtil.cursorToList(CursorUtil.java:44)
at com.my.project.MyFragment.getFields(MyFragment.java:230)
cursorToList()CursorUtil的方法
public static <T> ArrayList<T> cursorToList(Cursor cursor, Class<T> modelClass) {
ArrayList<T> items = new ArrayList<T>();
if (!isCursorEmpty(cursor)) {
while (cursor.moveToNext()) { <-- at this line (44) of the method raised that issue
final T model = buildModel(modelClass, cursor);
items.add(model);
}
}
return items;
}
【问题讨论】:
-
不是答案,但我强烈建议您查看sqlbrite。
-
@Lukasz,是的,我知道 sqlbrite,这将是一个很好的解决方案,但我无法将它添加到项目中,因为它已经很大并且使用了另一个 orm。
-
可以在处理之前的数据时更新此列表吗?
标签: android sqlite rx-java rx-android android-cursorloader