Ad

It Is Ok To Call ObserveForever() On Livedata Returned By Transformations.map() Inside ViewModel?

I tried to use LiveData Transformations.map() to check the result and update the UI. But Transformations.map() callback not triggered without an observer.

So is it good way to call observeForever {} on livedata returned by Tranformations.map? And remove obervers on onCleared on ViewModel?

private lateinit var map: LiveData<Unit>

    fun getAppConfiguration(): MutableLiveData<TopRatedMoviesResponse> {
        progressDialogVisibleLiveData.postValue(true)

        val appConfigurationLiveData = MutableLiveData<TopRatedMoviesResponse>()

        val appConfigurationSourceLiveData : MutableLiveData<DataResult> = splashScreenRepository.getAppConfiguration(getApplication())

        map = Transformations.map(appConfigurationSourceLiveData) { dataResult ->
            progressDialogVisibleLiveData.postValue(false)

            when (dataResult) {
                is DataResultSuccess -> {
                    appConfigurationLiveData.postValue(dataResult.data as TopRatedMoviesResponse)
                }

                is DataResultFailed -> {
                    when (dataResult.errorCode) {
                        HTTPError.NO_INTERNET -> {
                            errorDialogVisibleLiveData.postValue(dataResult)
                        }

                        HTTPError.BAD_REQUEST -> {
                            errorDialogVisibleLiveData.postValue(dataResult)
                        }

                        HTTPError.UNAUTHORISED -> {
                            unAuthorisedEventLiveData.postValue(true)
                        }

                        HTTPError.FORBIDDEN, HTTPError.NOT_FOUND, HTTPError.INTERNAL_SERVER_ERROR, HTTPError.UNKNOWN -> {
                            errorDialogVisibleLiveData.postValue(dataResult)
                        }
                    }
                }
            }
        }
        map.observeForever {  }

        return appConfigurationLiveData
    }

    override fun onCleared() {
        super.onCleared()

        map.removeObserver {  }
    }
Ad

Answer

But Transformations.map callback not triggered without observer.

It's normal, without the call to observerForever() the LiveData returned by Transformations.map() doesn't have anyone to offer the data that it holds.

So is it good way to call observeForever {} on livedata returned by Tranformations.map?

Looking at what you do in that method the answer is no, that's not how you use Transformations.map(). The goal of that method is to apply some changes to the values emitted by the source LiveData before those value are presented to an observer. In your case you want a simple type change(from dataResult.data to TopRatedMoviesResponse) along with triggering some error LiveDatas when something went wrong. Check the code below:

fun getAppConfiguration(): MutableLiveData<TopRatedMoviesResponse> {
    progressDialogVisibleLiveData.postValue(true)
    val appConfigurationSourceLiveData : MutableLiveData<DataResult> = splashScreenRepository.getAppConfiguration(getApplication())
    return Transformations.map(appConfigurationSourceLiveData) { dataResult ->
            progressDialogVisibleLiveData.postValue(false)
            when (dataResult) {
                is DataResultSuccess -> {
                    dataResult.data as TopRatedMoviesResponse
                }
                is DataResultFailed -> {
                    when (dataResult.errorCode) {                        
                        HTTPError.UNAUTHORISED -> {
                            unAuthorisedEventLiveData.postValue(true)
                        }
                        HTTPError.FORBIDDEN, HTTPError.NOT_FOUND, HTTPError.INTERNAL_SERVER_ERROR, HTTPError.UNKNOWN, HTTPError.NO_INTERNET, HTTPError.BAD_REQUEST -> {
                            errorDialogVisibleLiveData.postValue(dataResult)
                        }
                    }
                    // we have to return something even if an error occured
                    // I'm returning null, your UI should handle this
                    null 
                }                   
            }
     }
}

Also have a look at the architecture guide for alternative ways of handling data and errors with LiveData.

Ad
source: stackoverflow.com
Ad