Search code examples
androidandroid-livedatamutablelivedata

Android MediatorLiveData source subscription does not trigger


In my project I'm using a slightly modified repository pattern:

  • DataSource (e.g. API, database). Provides CRUD of entities
  • Repository of specific data (e.g. UserRepository, SettingsRepository) that handles reconciliation of DataSources (e.g. update database from API call). Provides basic functionality above CRUD
  • ViewModel that uses repositories and creates a flow out of the calls of repositories (e.g. use UserRepository to sync user data, then SettingsRepository to sync settings for the user)
  • View is databound

In my Repositories, I use exposed LiveData<*> fields to communicate state - e.g. said UserRepository would have a currentUser field of public type LiveData, privately MediatorLiveData, and it would be linked to a private field that holds the current user ID to be retrieved.

However, these subscriptions (using MediatorLiveData's addSource() {} method) for some reason do not fire.

An almost 1:1 example (replaced model name due to NDA) would be the following:

abstract class BaseRepository: ViewModel(), KoinComponent {

    val isLoading: LiveData<Boolean> = MutableLiveData<Boolean>().apply { postValue(false) }

}


class UserRepository: BaseRepository() {

    private val client: IClient by inject() // Koin injection of API client
    private val sharedPref: SharedPrefManager by inject() // custom wrapper around SharedPreferences

    private val currentUserId = MutableLiveData()

    val currentUser: LiveData<User> = MediatorLiveData()
    val users: LiveData<List<User>> = MutableLiveData()

    init {
        (currentUser as MediatorLiveData).addSource(currentUserId) { updateCurrentUser() }
        (currentUser as MediatorLiveData).addSource(users) { updateCurrentUser() }

        (currentUserId as MutableLiveData).postValue(sharedPref.getCurrentUserId())
        // sharedPref.getCurrentUserId() will return UUID? - null if 
    }

    fun updateCurrentUser() {
        // Here I have the logic deciding which user to push into `currentUser` based on the list of users, and if there's a `currentUserId` present.
    }
}

With this example implemented, updateCurrentUser() never gets called, even though the subscription to the other LiveData fields happens and is visible while debugging on the currentUser object.

The same subscription via addSource works just fine in other repositories, and they're constructed the very same way as above.

What could be going wrong here?


Solution

  • MediatorLiveData will not observe source LiveData if it does not have any observer subscribed to itself. updateCurrentUser() will be called as soon as you subscribe to currentUser.