Как сделать так, чтобы мое приложение получало данные из локальной сети, если соединение отсутствует, и из удаленной сети, если оно есть? - PullRequest
0 голосов
/ 01 сентября 2018

My MainRepository - это то, что выбирает данные из API и вставляет их в базу данных, а затем отображает в пользовательском интерфейсе.

override fun fetchAll() {
    Observable.fromCallable { local.fetchPosts() }
        .doOnNext {
            remote.fetchPosts().concatMap { posts ->
                local.insert(*posts.toTypedArray())
                Observable.just(posts)
            }
        }
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
            { outcome.success(it) },
            { error: Throwable -> outcome.failed(error) }
        ).addTo(compositeDisposable)
}

Переменная outcome представляет собой PublishObject типа Response, то есть Loading, Success или Failure.

override val outcome = PublishSubject.create<Response<List<Post>>>()

[...]

sealed class Response<T> {
    companion object {
        fun <T> loading(loading: Boolean): Response<T> = Progress(loading)
        fun <T> success(data: T): Response<T> = Success(data)
        fun <T> failure(e: Throwable): Response<T> = Failure(e)
    }

    data class Progress<T>(var loading: Boolean) : Response<T>()
    data class Success<T>(var data: T) : Response<T>()
    data class Failure<T>(var e: Throwable) : Response<T>()
}

Он выполняет метод local.fetchPosts(), который является функцией, отвечающей за доступ к функциям DAO.

fun fetchPosts() = database.postDao().fetchAll()

[...]

@Query("SELECT * FROM posts ORDER BY createdAt DESC")
fun fetchAll(): List<Post>

addTo является расширением Disposable:

fun Disposable.addTo(compositeDisposable: CompositeDisposable) {
    compositeDisposable.add(this)
}

Я пытался использовать concatMap сразу после Observable.fromCallable, но он будет отображать данные из API напрямую, а doOnNext будет отображаться из базы данных, но не будет обновлять список, удаляя то, что было удалено из удаленный сервер.

1 Ответ

0 голосов
/ 01 сентября 2018

Прежде всего вы должны понять, что doOnNext является оператором побочных эффектов , вместе с его семейством, операторы побочных эффектов только ожидают выбросы для выполнения незначительного действия (например, регистрации), они не не влияет на поток в любом случае.

Итак, с этим вы делаете наблюдаемое

remote.fetchPosts().concatMap { posts ->
            local.insert(*posts.toTypedArray())
            Observable.just(posts)
        }

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

  • Попробуйте получить данные из API.

  • в случае успешного кэширования, если нет - DAO

  • Показать

тогда как то будет работать:

remote.fetchPosts()
    // cache the data from remote.
    .doOnNext(posts -> local.insert(*posts.toTypedArray()))
    // if an error happens, use the posts in the DAO.
    .onErrorResumeNext { Observable.fromCallable { local.fetchPosts() } }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    [...]
...