Search code examples
androidkotlinmvvmviewmodelandroid-architecture-components

Whats the difference between observing a variable and a function


When I observe from Fragment A a variable in my viewmodel

val fetchTopicsList = liveData(Dispatchers.IO) {
        emit(Resource.Loading())
        try {
            emit(repo.getIdeas())
        }catch (e:Exception){
            emit(Resource.Failure(e))
        }
    }

And I navigate to Fragment B and come back to Fragment A the observer will fire again but the new data will not be fetched.

Now, if I change that declaration to a function declaration

fun fetchTopicsList() = liveData(Dispatchers.IO) {
        emit(Resource.Loading())
        try {
            emit(repo.getIdeas())
        }catch (e:Exception){
            emit(Resource.Failure(e))
        }
    }

When I do the same (go from Fragment A to Fragment B and come back) the observer will trigger again and pull the data again from the server.

Why the function fires again while the variable just keeps the first fetched data ?


Solution

  • You probably actually want a single instance of MutableLiveData which emits on some interaction, but I want to directly address your question:

    With the function, each invocation will give you a new instance of LiveData, whereas using a property initializer will instantiate + set it to a single instance of LiveData when your class is instantiated. This means that if your property is on a ViewModel it will survive through configuration changes and pause / resume cycles until it is destroyed.

    If you prefer the property syntax, you can make it do the same thing as when reinvoking the function each time, by overriding the getter, but honestly a function is more syntactically accurate here.

    This is how you would achieve the same functionality with property syntax:

    val fetchTopicsList: LiveData<..>
      get() = liveData(Dispatchers.IO) {
         emit(Resource.Loading())
         try {
           emit(repo.getIdeas())
         } catch (e:Exception){
           emit(Resource.Failure(e))
         }
      }
    

    Again, a better approach is probably a single MutableLiveData and exposing a function on ViewModel to make the request and post the value for any subscribers though.