热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CursorLoader的onLoadFinished回调中的RxJava2

如何解决《CursorLoader的onLoadFinished回调中的RxJava2》经验,为你挑选了1个好方法。

要从数据库中获取数据,我CursorLoader在应用程序中使用.一旦onLoadFinished()回调方法调用app的逻辑,就将Cursor对象转换为List业务模型需求中的对象.如果有大量数据,那么转换(繁重操作)需要一些时间.这会降低UI线程的速度.我尝试Thread使用RxJava2传递Cursor对象在非UI中启动转换,但得到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 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 loader, Cursor cursor) {
        if (cursor.getCount() > 0) {
            getFieldsObservable(cursor)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(this::showFields);
        } else {
            showNoData();
        }
    }

private static Observable> getFieldsObservable(Cursor cursor) {
            return Observable.defer(() -> Observable.just(getFields(cursor))); <-- Exception raised at this line

        }

private static List getFields(Cursor cursor) {
            List 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)

cursorToList() 的方法 CursorUtil

public static  ArrayList cursorToList(Cursor cursor, Class modelClass) {
        ArrayList items = new ArrayList();
        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;
    }

azizbekian.. 6

从我对您的问题的评论中可以看出,我对getFieldsObservable()尚未返回的数据是否正在更新感兴趣.我收到了您对评论感兴趣的信息.

我可以判断,这是你的情况:

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 {
  ...
  /* 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`
      List list = CursorUtil.cursorToList(cursor, Field.class);
      return new PojoWrapper(cursor, list);
    } finally {
      ...
    }
  }
  ...
}

在哪里PojoWrapper:

public class PojoWrapper {
  Cursor cursor;
  List list;

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

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

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

这是整个代码MyCustomLoader.



1> azizbekian..:

从我对您的问题的评论中可以看出,我对getFieldsObservable()尚未返回的数据是否正在更新感兴趣.我收到了您对评论感兴趣的信息.

我可以判断,这是你的情况:

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 {
  ...
  /* 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`
      List list = CursorUtil.cursorToList(cursor, Field.class);
      return new PojoWrapper(cursor, list);
    } finally {
      ...
    }
  }
  ...
}

在哪里PojoWrapper:

public class PojoWrapper {
  Cursor cursor;
  List list;

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

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

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

这是整个代码MyCustomLoader.


推荐阅读
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • switch语句的一些用法及注意事项
    本文介绍了使用switch语句时的一些用法和注意事项,包括如何实现"fall through"、default语句的作用、在case语句中定义变量时可能出现的问题以及解决方法。同时也提到了C#严格控制switch分支不允许贯穿的规定。通过本文的介绍,读者可以更好地理解和使用switch语句。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
author-avatar
Luna--moon
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有