gpt4 book ai didi

android - CursorLoader 的 onLoadFinished 回调中的 RxJava2

转载 作者:IT王子 更新时间:2023-10-29 06:20:13 30 4
gpt4 key购买 nike

为了从数据库中获取数据,我在应用程序中使用了 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 的目的是在有数据存储更新时从 DB 获得通知。

更新正如 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)
CursorUtil

cursorToList() 方法

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;
}

最佳答案

my comment可以看出对于您的问题,我感兴趣的是数据是否正在更新,而 getFieldsObservable() 尚未返回。我收到了我感兴趣的信息in your comment .

据我判断,您的情况如下:

  • onLoadFinished()用 Cursor-1 调用
  • RxJava的方法正在另一个线程上用Cursor-1执行(还没完,这里用的是Cursor-1)
  • onLoadFinished()使用 Cursor-2 调用,LoaderManager API 负责关闭 Cursor-1,它仍在另一个线程上被 RxJava 查询

因此,异常结果。

因此,您最好坚持创建自定义 AsyncTaskLoader (CursorLoader 延伸自)。这AsyncTaskLoader将包含 CursorLoader 的所有逻辑有(基本上是一对一的副本),但会在 onLoadFinished(YourCustomObject) 中返回已经排序/过滤的对象。因此,您希望使用 RxJava 执行的操作实际上将由您的加载程序在其 loadInBackground() 中完成。方法。

下面是 MyCustomLoader 将在 loadInBackground() 方法中进行更改的快照:

public class MyCustomLoader extends AsyncTaskLoader<PojoWrapper> {
...
/* Runs on a worker thread */
@Override
public PojoWrapper loadInBackground() {
...
try {
Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
mSelectionArgs, mSortOrder, mCancellationSignal);
...

// `CursorLoader` performs following:
// return cursor;

// We perform some operation here with `cursor`
// and return PojoWrapper, that consists of `cursor` and `List<Pojo>`
List<Pojo> list = CursorUtil.cursorToList(cursor, Field.class);
return new PojoWrapper(cursor, list);
} finally {
...
}
}
...
}

PojoWrapper 是:

public class PojoWrapper {
Cursor cursor;
List<Pojo> list;

public PojoWrapper(Cursor cursor, List<Pojo> list) {
this.cursor = cursor;
this.list = list;
}
}

因此,在 onLoadFinished()您不必负责将工作委托(delegate)给另一个线程,因为您已经在 Loader 中完成了它实现:

@Override public void onLoadFinished(Loader<PojoWrapper> loader, PojoWrapper data) {
List<Pojo> alreadySortedList = data.list;
}

Here's MyCustomLoader 的完整代码。

关于android - CursorLoader 的 onLoadFinished 回调中的 RxJava2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44390030/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com