我们如何处理房间生成的分页代码的运行时错误?

Com*_*are 6 android android-room android-paging

这个示例项目中,我有一个 DAO,它在 FTS4 表上使用 Paging 2 来搜索它,使用用户提供的搜索表达式:

  @Query("SELECT snippet(paragraphsFts) FROM paragraphs JOIN paragraphsFts "+
      "ON paragraphs.id == paragraphsFts.rowid WHERE paragraphsFts.prose "+
      "MATCH :search ORDER BY sequence")
  abstract fun filtered(search: String): DataSource.Factory<Int, String>
Run Code Online (Sandbox Code Playgroud)

我有一个BookRepositoryfiltered()函数,它只是通过对 DAO 的调用,我有一个SearchViewModel将 the 转换DataSource.Factory为 a的函数LiveData

class SearchViewModel(search: String, repo: BookRepository) : ViewModel() {
  val paragraphs = repo.filtered(search).toLiveData(pageSize = 15)
}
Run Code Online (Sandbox Code Playgroud)

我有一个观察结果的片段

    vm.paragraphs.observe(this.viewLifecycleOwner) {
      adapter.submitList(it)
    }
Run Code Online (Sandbox Code Playgroud)

只要用户没有输入语法错误的搜索表达式,这就可以正常工作。在这种情况下,Room 会抛出异常,我看不到在哪里可以捕获它。

2020-08-30 08:50:50.923 13948-14019 E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_3
    Process: com.commonsware.room.pagedfts, PID: 13948
    android.database.sqlite.SQLiteException: malformed MATCH expression: [-9] (code 1 SQLITE_ERROR)
        at android.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:942)
        at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:838)
        at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
        at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:153)
        at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:140)
        at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:232)
        at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:271)
        at androidx.room.paging.LimitOffsetDataSource.countItems(LimitOffsetDataSource.java:89)
        at androidx.room.paging.LimitOffsetDataSource.loadInitial(LimitOffsetDataSource.java:119)
        at androidx.paging.PositionalDataSource.dispatchLoadInitial(PositionalDataSource.java:286)
        at androidx.paging.TiledPagedList.<init>(TiledPagedList.java:107)
        at androidx.paging.PagedList.create(PagedList.java:229)
        at androidx.paging.PagedList$Builder.build(PagedList.java:388)
        at androidx.paging.LivePagedListBuilder$1.compute(LivePagedListBuilder.java:206)
        at androidx.paging.LivePagedListBuilder$1.compute(LivePagedListBuilder.java:171)
        at androidx.lifecycle.ComputableLiveData$2.run(ComputableLiveData.java:101)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
Run Code Online (Sandbox Code Playgroud)

异常发生在由LiveData创建者使用的后台线程上toLiveData()。所以我声明中的try/将不起作用,因为在创建. 将我的调用包装在/中不起作用,因为该线程上未引发异常。catchparagraphsLiveDataobserve()trycatch

如果我没有使用 Paging,而是让我的 DAO 的filtered()函数是一个suspend函数,我会直接得到异常并且可以在视图模型中捕获和处理它。或者,如果filtered()是阻塞调用,我会直接得到异常。或者,如果filtered()返回 RxJava 类型,我将通过正常的 RxJava 异常处理方法(例如,onErrorlambdas)获取异常。但是我无法弄清楚在使用 Paging 时应该在哪里拦截这个异常。

Paging 3 可能对此有一个解决方案,这很高兴知道,尽管 Paging 3 现在仍处于 alpha 阶段。

虽然我没有尝试过,但我怀疑如果我提供自己ExecutortoLiveData(),我可以在那里捕获异常。即使这是一种可能的解决方法,这似乎也是我依赖的副作用(取代了我们在线程上安排工作以能够捕获异常的方式)。