Search code examples
androidkotlinandroid-databindingandroid-architecture-componentsmutablelivedata

Best way to execute custom logic when setting value to MutableLiveData


What is the most recommended approach to execute custom logic when setting value of MutableLiveData?

I have a ViewModel with several properties isConnecting and isConnected. I want to set isConnecting to false when isConected is changed

class MyViewModel : ViewModel() {
    private var _isConnecting = MutableLiveData<Boolean>()
    val isConnecting: LiveData<Boolean>
        get () = _isConnecting
    
    private var _isConnected = MutableLiveData<Boolean>()
    val isConnected: LiveData<Boolean>
        get () = _isConnected
}

One way to do it is creating a function inside MyViewModel and set both properties:

fun setConnected(value: Boolean) {
    _isConnected.value = value
    _isConnecting.value = false
}

This is okay, but one must never set _isConnected manually and always use function setConnected(). It can not be guaranteed and thus there may be bugs.

Another way to do it is to make MyViewModel observe its own MutableLiveData:

class MyViewModel : ViewModel() {

    // ...

    private val isConnectedObserver = Observer<Boolean> {
        _isConnecting.value = false
    }

    init {
        isConnected.observeForever(isConnectedObserver)
    }

    override fun onCleared() {
        super.onCleared()
        isConnected.removeObserver(isConnectedObserver)
    }
}

This avoids problem of first approach, but is just awful.

But is there a better way? For example using setters somehow?


Solution

  • Use MediatorLiveData to observe other LiveData objects and react on onChanged events from them:

    class MyViewModel : ViewModel() {
    
        private var _isConnecting = MediatorLiveData<Boolean>().also { liveData ->
            liveData.addSource(_isConnected) { connected ->
                // isConnected changed, some logic here
                if (connected) {
                    liveData.value = false
                }
            }
        }
        val isConnecting: LiveData<Boolean>
            get() = _isConnecting
    
        private var _isConnected = MutableLiveData<Boolean>()
        val isConnected: LiveData<Boolean>
            get() = _isConnected
    }