Библиотека подкачки: сохранение данных в БД не вызывает изменения пользовательского интерфейса - PullRequest
0 голосов
/ 29 мая 2018

Итак, я играю с новой библиотекой подкачки Android , входящей в состав инструментов JetPack.

Я делаю очень простое демонстрационное приложение, в котором я показываю список случайных пользовательских профилей.что я получаю от RandomUser API.

Дело в том, что у меня все настроено, и это на самом деле вроде работает.

В моем фрагменте списка я слушаю изменения БД:

...
mainViewModel.userProfiles.observe(this, Observer { flowableList ->
            usersAdapter.submitList(flowableList) })
...

(я пробовал с обоими, используя Flowables и Observables с RxPagedListBuilder и сейчасЯ использую LiveData с LivePagedListBuilder. Я хотел бы использовать RxPagedListBuilder, если это возможно)

В моей ViewModel я устанавливаю LivePagedListBuilder

...
private val config = PagedList.Config.Builder()
        .setEnablePlaceholders(false)
        .setPrefetchDistance(UserProfileDataSource.PAGE_SIZE / 2) //Is very important that the page size is the same everywhere!
        .setPageSize(UserProfileDataSource.PAGE_SIZE)
        .build()

val userProfiles: LiveData<PagedList<UserProfile>> = LivePagedListBuilder(
        UserProfileDataSourceFactory(userProfileDao), config)
        .setBoundaryCallback(UserProfileBoundaryCallback(randomUserRepository, userProfileDao))
        .build()
...

Я установил DataSource для извлечения данных из моей БД (если есть):

class UserProfileDataSource(val userDao: UserDao): PageKeyedDataSource<Int, UserProfile>() {

    companion object {
        const val PAGE_SIZE = 10
    }

    override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, UserProfile>) {
        callback.onResult(userDao.getUserProfileWithLimitAndOffset(PAGE_SIZE, 0), 0, PAGE_SIZE)
    }

    override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, UserProfile>) {
        callback.onResult(userDao.getUserProfileWithLimitAndOffset(PAGE_SIZE, params.key), params.key + PAGE_SIZE)
    }

    override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, UserProfile>) {
        //This one is not used
    }
}

И я установил BoundaryCallback для извлечения данных из сети, если база данных пуста:

class UserProfileBoundaryCallback(val userRepository: RandomUserRepository,
                                  val userDao: UserDao) : PagedList.BoundaryCallback<UserProfile>() {


    /**
     * Database returned 0 items. We should query the backend for more items.
     */
    override fun onZeroItemsLoaded() {
        userRepository.getUserProfiles(0, UserProfileDataSource.PAGE_SIZE)
            .subscribeOn(Schedulers.io()) //We shouldn't write in the db over the UI thread!
            .subscribe(object: DataSourceSubscriber<List<UserProfile>>() {
                override fun onResultNext(userProfiles: List<UserProfile>) {
                    userDao.storeUserProfiles(userProfiles)
                }
            })
    }

    /**
     * User reached to the end of the list.
     */
    override fun onItemAtEndLoaded(itemAtEnd: UserProfile) {
        userRepository.getUserProfiles(itemAtEnd.indexPageNumber + 1, UserProfileDataSource.PAGE_SIZE)
            .subscribeOn(Schedulers.io()) //We shouldn't write in the db over the UI thread!
            .subscribe(object: DataSourceSubscriber<List<UserProfile>>() {
                override fun onResultNext(userProfiles: List<UserProfile>) {
                    userDao.storeUserProfiles(userProfiles)
                }
            })
    }

}

Дело в том, что Flowable, Observable или LiveData в пользовательском интерфейсе запускаются только в том случае, если данные поступают из базы данных, когда UserProfileDataSource возвращает некоторый результат из базы данных,Если UserProfileDataSource не возвращает никакого результата, вызывается BoundaryCallback, запрос к API успешно выполнен, данные сохраняются в базе данных, но Flowable никогда не срабатывает.Если я закрою приложение и снова открою его, он получит данные, которые мы только что получили из базы данных, а затем правильно отобразит их.

Я испробовал все возможные решения, которые видел во всехстатьи, учебные пособия и проекты github, которые я искал.

Как я уже говорил, я пытался изменить RxPagedListBuilder на LivePagedListBuilder.

При использовании RxPagedListBuilder я пробовал с обоими, Flowables и Observables.

Я пытался установить различные конфигурации для PagedList.Config.Builder с использованием разных планировщиков.

У меня действительно нет вариантов, я весь день боролсяс этим, любой совет будет оценен.

Если вам нужна дополнительная информация о коде, просто оставьте мне комментарий, и я обновлю сообщение.

Обновление:

Я отправил полный исходный код в мое Github репо

Ответы [ 2 ]

0 голосов
/ 02 августа 2019

Если вы реализуете DataSource, вам нужно каждый раз вызывать DataSource # invalidate () после базы данных операционной комнаты.

0 голосов
/ 30 мая 2018

Хорошо, я обнаружил ошибку:

Я только что удалил классы UserProfileDataSourceFactory и UserProfileDataSource.Вместо этого я добавил этот метод в свой DAO:

@Query("SELECT * FROM user_profile")
fun getUserProfiles(): DataSource.Factory<Int, UserProfile>

И я создаю свой RxPagedListBuilder как:

RxPagedListBuilder(userDao.getUserProfiles(), UserProfileDataSource.PAGE_SIZE)
        .setBoundaryCallback(UserProfileBoundaryCallback(randomUserApi, userDao))
        .buildObservable()

И это все.Я не уверен, почему он не работает с DataSource и DataSourceFactory, если кто-то может объяснить это странное поведение, я отмечу этот ответ как принятый, так как мое решение было больше похоже на удачный выстрел.

OneОднако сейчас происходит то, что когда я загружаю данные в адаптер, адаптер прокручивается обратно в верхнее положение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...