Search code examples
androidrx-java2android-livedataandroid-mvvm

In Android, Make a list of api call inside one api call


In one of my android app, at first I want to call an api, which will return a list of item, and the item will be shown in a RecyclerView. I also need to call another api for each item of the RecyclerView to fetch description of that item and show the description to each item according to their id. How can I resolve this scenario.

Subject.kt

data class Subject(
    val subject: String,
    val subjectCode:String,
    val subjectIcon: String,
    val progress: Double = 0.0,
)

SubjectRepository.kt

interface SubjectRepository {
    fun getAllSubject(): Observable<List<Subject>>
    fun getProgressAnalysisOf(subjectCode: String): Observable<Double>
}

SubjectViewModel.kt

class HomeViewModel @Inject constructor(
    private val subjectRepository: SubjectRepository,
) : BaseViewModel() {

    val subjectList = MutableLiveData<List<Subject>>()
    val progress = MutableLiveData<Double>

    fun getAllSubject() {
        compositeDisposable += subjectRepository.getAllSubject()
            .performOnBackgroundOutputOnMain()
            .doOnSubscribe { loader.value = true }
            .doAfterTerminate { loader.value = false }
            .subscribe({
                subjectList.value = it
            }, {
                handleException(it)
            })
    }

    fun getProgressAnalysisOf(subjectCode: String) {
        compositeDisposable += subjectRepository. getProgressAnalysisOf(subjectCode)
            .performOnBackgroundOutputOnMain()
            .doOnSubscribe { loader.value = true }
            .doAfterTerminate { loader.value = false }
            .subscribe({
                progress.value = it
            }, {
                handleException(it)
            })
    }
}

first I need to call getAllSubject() which will return a list of Subject and I show this list in my RecyclerView. And for each subject of the recycler view, I have to call getProgressAnalysisOf(subjectCode) and update the item of that recyclerView.


Solution

  • Finally, I got a solution. I used ConnectableObservable to solve this issue.

    1. You can notice replay() operator (getAllSubject().replay()) is used to make an Observable emits the data on new subscription without re-executing the logic again.
    2. In my case, the list of subject will be emitted without making the HTTP call again. Without the replay method, you can notice that getAllSubject() HTTP call get executed multiple times.
    3. In the first subscription, the list of subject directly added to Adapter class and the RecyclerView is rendered directly without progressValue of subjects.
    4. In the second subscription, flatMap() is used to convert list of subject to individual subject emission.
    5. On the same Observable, another flatMap is chained to execute the getProgressAnalysisOf() method on each subject emission which fetches the progress value.
    6. Once the progress information is received, the particular row item is updated in RecyclerView.

    HomeViewModel.kt

    class HomeViewModel @Inject constructor(
        private val subjectRepository: SubjectRepository,
    ) : BaseViewModel() {
    
        val subjectList = MutableLiveData<List<Subject>>()
        val progress = MutableLiveData<Double>
        var subjectsObservable: ConnectableObservable<List<Subject>> = subjectRepository.getAllSubject().replay()
    
        fun getAllSubject() {
            compositeDisposable += subjectsObservable
            .performOnBackgroundOutputOnMain()
            .doOnSubscribe { loader.value = true }
            .doAfterTerminate { loader.value = false }
            .subscribe({
                subjectList.value = it
            }, {
                handleException(it)
            })
        }
    
        fun getProgressAnalysisOf() {
            compositeDisposable += subjectsObservable
            .performOnBackgroundOutputOnMain()
            .flatMap { Observable.fromIterable(it) }
            .flatMap { subjectRepository.getProgressAnalysisOf(it.code) }
            .subscribe({
                analysisData.postValue(it)
            }, {
                handleException(it)
            })
    }
    

    HomeActivity.kt

    class HomeFragment : BaseFragment<HomeViewModel>() {
    
        private val subjectAdapter: SubjectAdapter by lazy {
            SubjectAdapter {
    
            }
        }
    
        override fun onResume() {
            super.onResume()
    
            viewModel.getAllSubject()
            viewModel.getPerformanceAnalysisOf()
            viewModel.subjectsObservable.connect()
        }
    
        override fun observeLiveData() {
            observe(viewModel.subjectList) {
                subjectAdapter.submitList(it)
            }
    
            observe(viewModel.analysisData) {
                // update the analysis value for each item
            }
        }
    }