Отображение ProgressBar с Paging Library, когда источником данных является база данных Room - PullRequest
0 голосов
/ 09 марта 2020

Операции с запросами к моей базе данных могут занимать много времени, поэтому я хочу отображать ProgressBar во время выполнения запроса. Это особенно проблема, когда пользователь изменяет параметры сортировки, потому что он отображает старый список некоторое время, пока не появится новый список и не обновится RecyclerView. Я просто не знаю, где захватить состояния Загрузка и Успех для такого запроса.

Вот мой метод получения 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.Factory? Если так, я понятия не имею, с чего начать. Я полагаю, что это будет PositionalDataSource, но я не могу найти в Интернете никаких примеров для реализации пользовательского.

Я также попытался adapter.registerAdapterDataObserver() на своем адаптере RecyclerView. Это вызывает различные обратные вызовы, когда отображаются новые данные списка, но я не могу отличить их от обратных вызовов, когда загрузка началась и остановилась.

1 Ответ

0 голосов
/ 10 марта 2020

В конечном итоге я смог это исправить, наблюдая за 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)
        }
    }
}
...