【问题标题】:Displaying ProgressBar with Paging Library when Room database is the data source当 Room 数据库为数据源时,使用 Paging Library 显示 ProgressBar
【发布时间】:2020-03-08 22:20:24
【问题描述】:

我的数据库查询操作可能需要很长时间,所以我想在查询进行时显示一个 ProgressBar。当用户更改排序选项时,这尤其是一个问题,因为它会显示旧列表一段时间,直到新列表出现并更新 RecyclerView。我只是不知道在哪里为这样的查询捕获 Loading 和 Success 状态。

这是我从数据库中获取 PagedList 的方法:

fun getGameList(): LiveData<PagedList<Game>> {

    // Builds a SimpleSQLiteQuery to be used with @RawQuery
    val query = buildGameListQuery()

    val dataSourceFactory: DataSource.Factory<Int, Game> = database.gameDao.getGameList(query)

    val data: LiveData<PagedList<Game>> = LivePagedListBuilder(dataSourceFactory, DATABASE_PAGE_SIZE)
        .build()

    return data
}

我通过观察这个来更新我的列表:

val games = Transformations.switchMap(gameRepository.sortOptions) {
    gameRepository.getGameList()
}

我需要自定义 DataSource 和 DataSource.Factory 吗?如果是这样,我什至不知道从哪里开始。我相信这将是一个 PositionalDataSource,但我在网上找不到任何实施自定义示例的示例。

我还在我的 RecyclerView 适配器上尝试了adapter.registerAdapterDataObserver()。这会在显示新列表数据时触发各种回调,但我无法辨别加载开始和停止时的回调。

【问题讨论】:

    标签: android android-room android-architecture-components android-paging android-paging-library


    【解决方案1】:

    我最终能够通过观察games LiveData 来解决这个问题。然而,这并不完全简单。

    这是我的 DatabaseState 类:

    sealed class DatabaseState {
    
        object Success : DatabaseState()
    
        object LoadingSortChange: DatabaseState()
    
        object Loading: DatabaseState()
    }
    

    捕获加载状态很容易。每当用户更新排序选项时,我都会调用这样的方法:

    fun updateSortOptions(newSortOptions: SortOptions) {
        _databaseState.value = DatabaseState.LoadingSortChange
        _sortOptions.value = newSortOptions
    }
    

    成功状态是一个棘手的状态。由于我的排序选项包含在 RecyclerView 的单独片段中,games LiveData 观察者在保存新的排序选项时会触发两次(一次在 ListFragment 恢复时,然后在数据库查询完成后再次触发)。所以我不得不这样解释:

    /**
     * The observer that triggers this method fires once under normal circumstances, but fires
     * twice if the sort options change. When sort options change, the "success" state doesn't occur
     * until the second firing. So in this case, DatabaseState transitions from LoadingSortChange to
     * Loading, and finally to Success.
     */
    fun updateDatabaseState() {
        when (databaseState.value) {
            Database.LoadingSortChange -> gameRepository.updateDatabaseState(DatabaseState.Loading)
            DatabaseState.Loading -> gameRepository.updateDatabaseState(DatabaseState.Success)
        }
    }
    

    最后,我需要对我的 BindingAdapter 进行一些更改以解决一些剩余的问题:

    @BindingAdapter("gameListData", "databaseState")
    fun RecyclerView.bindListRecyclerView(gameList: PagedList<Game>?, databaseState: DatabaseState) {
        val adapter = adapter as GameGridAdapter
    
        /**
         * We need to null out the old list or else the old games will briefly appear on screen
         * after the ProgressBar disappears.
         */
        adapter.submitList(null)
    
        adapter.submitList(gameList) {
            // This Runnable moves the list back to the top when changing sort options
            if (databaseState == DatabaseState.Loading) {
                scrollToPosition(0)
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-02
      • 2020-10-29
      • 1970-01-01
      • 2020-05-18
      • 1970-01-01
      • 1970-01-01
      • 2017-11-09
      相关资源
      最近更新 更多