Чтобы получить данные из базы данных, я использую CursorLoader
в приложении. После того как метод обратного вызова onLoadFinished()
вызывает логику приложения, он преобразует объект Cursor
в объект List
объектов в рамках требований бизнес-модели. Это преобразование (тяжелая операция) занимает некоторое время, если имеется много данных. Это замедляет поток пользовательского интерфейса. Я попытался запустить преобразование в не-UI Thread
с помощью RxJava2
передачи Cursor
объекта, но получил 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
здесь - получить уведомления от БД, если обновление данных обновлено.
Обновление
Как предположил Тин Тран, я удалил 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;
}