Есть ли лучший способ реализовать единый источник правды с помощью rx java в android - PullRequest
0 голосов
/ 22 апреля 2020

В моем приложении у меня есть база данных, которая использует Room и сетевой сервис, использующий модернизацию. У меня есть требование, когда, если в локальной базе данных нет данных, мне нужно запросить сеть и показать индикатор выполнения. Если сеть возвращает пустые данные, мне нужно показать пустое представление. Одна из проблем заключается в том, что мне нужно игнорировать пустые данные из комнаты и рассматривать только пустые данные с сервера, поэтому, когда у пользователя нет никаких данных, он просто видит представление загрузки, а после того, как сервер возвращает пустые данные, он будет см. пустое представление.

Я реализовал это, используя публичную sh тему. Lce (ошибка загрузки содержимого) является объектом-оболочкой для данных.

val recentPublish = PublishSubject.create<Lce<List<RecentMessage>>>()

fun loadRecentMessages() {
        loadMessageFromDB()
        loadRecentMessageFromServer()
}
private fun loadMessageFromDB() {
    disposable = recentMessageDao.getRecentMessages() // this is a flowable
        .subscribeOn(Schedulers.io())
        .subscribe({
            Timber.d("recent message from db size ${it.size}")
            handleMessageFromDB(it)
        }, {
            it.printStackTrace()
            Timber.e("error on flowable from db!")
        })
}
protected fun handleMessageFromDB(messages: List<RecentMessage>) {
    // only publish if the data is not empty
    if (messages.isNotEmpty()) {
        recentPublish.onNext(Lce.Content(messages))
    }
}

private fun loadRecentMessageFromServer() {
    recentPublish.onNext(Lce.Loading())
    networkService.getLatestMessage() // this is a single
        .subscribe({
            val parsedMessages =
                DtoConverter.convertRecentPrivateMessageResponse(it, user.id!!)
            handleMessageFromServer(parsedMessages)
        }, {
            it.printStackTrace()
            recentPublish.onNext(Lce.Error(it))
            Timber.w("failed to load recent message for private chat from server")
        })
}

private fun handleMessageFromServer(recentMessages: List<RecentMessage>) {
    Timber.i("recent messages from server ${recentMessages.size}")
    if (recentMessages.isEmpty()) {
        recentPublish.onNext(Lce.Content(arrayListOf()))
    } else {
        recentMessageDao.saveAll(recentMessages)
    }
}

В приведенном выше коде я передаю только пустые данные с сервера и игнорирую пустые данные из комнаты. Это решение работает, но мне интересно, есть ли лучший функциональный подход для решения этой проблемы. Я новичок в Rx java, и любая помощь будет оценена. Спасибо.

1 Ответ

1 голос
/ 23 апреля 2020

После некоторого исследования и комментария от @EpicPandaForce я пришел к такому подходу. Я узнал довольно мало вещей, и мне просто показалось, как правильно использовать rx java. Вот мой подход, любой комментарий будет оценен.

    fun getMessages(): Observable<Lce<List<RecentMessage>>> {
        return Observable.mergeDelayError(getMessagesFromDB(), getMessagesFromNetwork()) // even if network fails, we still want to observe the DB
    }

    private fun getMessagesFromDB(): Observable<Lce.Content<List<RecentMessage>>> {
        return recentMessageDao.getRecentMessages()
            .filter {
                it.isNotEmpty() // only forward the data from db if it's not empty
            }.map {
                Lce.Content(it)
            }
    }

    private fun getMessagesFromNetwork(): Observable<Lce<List<RecentMessage>>> {
        // first show a loading , then request for data
        return Observable.concat(Observable.just(Lce.Loading()), profileService.getLatestMessage()
                .flatMap {
                    processServerResponse(it) // store the data to db
                }.onErrorReturn {
                    Lce.Error(it)
                }.filter {
                    (it as Lce.Content).packet.isEmpty() // only forward data if it's empty
                })
    }


    private fun processServerResponse(response: RecentMessageResponse): Observable<Lce<List<RecentMessage>>> {
        return Observable.create {
            val parsedMessages =
                DtoConverter.convertRecentPrivateMessageResponse(response, user.id!!)
            handleMessageFromServer(parsedMessages)
            it.onComplete() // we use single source of truth so don't return anyting
        }
    }
...