Как объединить несколько наблюдаемых в rxjava - PullRequest
0 голосов
/ 09 апреля 2020

Как объединить несколько различных наблюдаемых и подписаться из viewmodel?

Я использую принцип единого источника истины, поэтому сначала я получаю данные из базы данных, затем загружаю данные из веб-сервиса и, наконец, сохраняю все данные в базу данных.

Для этого я использовал библиотеки rx java, room, dagger2, retrofit. Но была какая-то проблема. Я должен получить несколько списков из веб-сервиса и сохранить каждый список в базу данных. Я пробую какое-то решение, но этот код отвечает на один и тот же запрос несколько раз. Прогрессбар меняется каждый раз. Как я могу упростить? Лучшие практики для этого.

API. json

{
"data": {
        "ad": [
            {
                "id": 11,
                "image": "ad/ru/msG0y8vuXl.png"
            }
            ...
        ],
        "categories": [...],
        "status":     [...],
        "location":   [...]
        }
}

HomeRepository.kt

class HomeRepository @Inject constructor(
    private val indexApi: IndexApi, 
    private val categoryDao: CategoryDao, 
    private val userDao: UserDao, 
    private val adDao: AdDao
) {

    fun getCategoryList(): Observable<List<Category>> {
        val categoryListDb: Observable<List<Category>> = categoryDao.getCategoryList()
            .filter { t: List<Category> -> t.isNotEmpty() }
            .subscribeOn(Schedulers.computation())
            .toObservable()

        val categoryListApi: Observable<List<Category>> = indexApi.getIndex()
            .toObservable()
            .map { response ->
                Observable.create { subscriber: ObservableEmitter<Any> ->
                    categoryDao.insertCategoryList(response.data.categories)
                    subscriber.onComplete()
                }
                    .subscribeOn(Schedulers.computation())
                    .subscribe()
                response.data.categories
            }
            .subscribeOn(Schedulers.io())

        return Observable
            .concatArrayEager(categoryListDb, categoryListApi)
            .observeOn(AndroidSchedulers.mainThread())
    }

    fun getUserList(): Observable<List<User>> {
        // same as above
    }

    fun getAdList(): Observable<List<Ad>> {
        // same as above
    }
}

HomeViewmodel.kt

class HomeViewModel @Inject constructor(
    private val homeRepository: HomeRepository
) : BaseViewModel() {

    private val categoryLiveData: MutableLiveData<Resource<List<Category>>> = MutableLiveData()
    private val adLiveData: MutableLiveData<Resource<List<Ad>>> = MutableLiveData()
    private val userLiveData: MutableLiveData<Resource<List<User>>> = MutableLiveData()

    fun categoryResponse(): LiveData<Resource<List<Category>>> = categoryLiveData
    fun adResponse(): LiveData<Resource<List<Ad>>> = adLiveData
    fun userResponse(): LiveData<Resource<List<User>>> = userLiveData

    fun loadCategory() {
        categoryLiveData.postValue(Resource.loading())
        compositeDisposable.add(
            homeRepository.getCategoryList()
                .subscribe({ response ->
                    categoryLiveData.postValue(Resource.succeed(response))
                }, { error ->
                    categoryLiveData.postValue(Resource.error(error))
                })
        )
    }
    fun loadAd() { // Same as above }
    fun loadUser() { // Same as above }
}

HomeFragment .kt

fun init(){
    // ..
    viewmodel.loadCategory()
    viewmodel.adResponse()
    viewmodel.userResponse()

    viewmodel.categoryResponse().observe(this, Observer {
        when(it.status){
        Status.SUCCEED -> { progressBar.toGone() }
        Status.LOADING -> { progressBar.toVisible() }
        Status.FAILED  -> { progressBar.toGone() }
        }
    }
    viewmodel.adResponse().observe(this, Observer { //Same as above }
    viewmodel.userResponse().observe(this, Observer { //Same as above }
}

1 Ответ

0 голосов
/ 17 апреля 2020

Вы должны быть в состоянии предотвратить множественные вызовы в вашем коде, обернув indexApi.getIndex().toObservable() внутри подключаемой наблюдаемой.

Это немного больше продвинутого topi c, но примерно то, что вам нужно Чтобы сделать это:

Создайте поле в своем классе HomeRepository:

private val observable = Observable.defer {
  indexApi.getIndex().toObservable()
}.replay(1).refCount()

И затем вам необходимо заменить каждое использование indexApi.getIndex().toObservable() на observable.

Это может не совсем достичь ожидаемого вами результата. Этот пост в блоге, кажется, представляет собой список других возможных вариантов: https://blog.danlew.net/2016/06/13/multicasting-in-rxjava/

...