Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to propagate Livedata from Repository > ViewModel > Fragment

getMoreData() in ViewModel is called from outside of ViewModel, everytime user scroll to the bottom of RecyclerView.

fetchMore() in Repository returns a LiveData with LoadingStatus object which contains loading/success/failure and error message

How can I set the loadingStatus variable in ViewModel so that it can be observed properly by the Fragment?

Note: getMoreData() in ViewModel can be called multiple times as the user scrolls down.

ViewModel{
    val loadingStatus

    fun getMoreData(){
        repository.fetchMore()
    }
}

Repository{
    fun fetchMore() : LiveData<LoadingStatus>{

    }
}

Fragment{
    viewModel.loadingStatus.observe()
}
like image 945
Ashesh Bharadwaj Avatar asked Nov 07 '22 02:11

Ashesh Bharadwaj


1 Answers

The issue is with the need for a Lifecycle Owner used for observations of LiveData in the Repository.

First, you don't want to return a new LiveData<LoadingStatus> every time fetchMore() is called. That would create a new LiveData each time. Best case, you would want the function fetchMore() do some something like this, updating a single LiveData:

Repository{
    val status = LiveData<LoadingStatus>()

    fun fetchMore() {
        status.postValue(LOADING)

        // Pseudo code for actually loading more items

        status.postValue(FINISHED LOADING)
    }
}

However, you will have the issue of observing the status from the ViewModel as it itself is not a Lifecycle implementation, so it cannot easily observe the LiveData from the Repository.

My suggestion would be something like this:

ViewModel{
    val loadingStatus: MutableLiveData<LoadingStatus>

    init{
        repository.observeStatus()
            .subscribe( event -> loadingStatus.postValue(event))
    }

    fun getMoreData(){
        repository.fetchMore()
    }
}

Repository{
    val status = BehaviorSubject.create<LoadingStatus>()

    fun observeStatus(): Observable<LoadingStatus> {
        return status
    }

    fun fetchMore(){
        status.onNext(LOADING)

        // Pseudo code for actually loading more items

        status.onNext(FINISHED LOADING)
    }
}

Fragment{
    viewModel.loadingStatus.observe()
}

Note that you will have to dispose the subscription in the ViewModel onCleared.
Note that all of this is pseudo code and it should be done a lot cleaner than this.

like image 154
Bam Avatar answered Nov 21 '22 04:11

Bam