2

I'm following the MVVM architecture in my android app. (https://developer.android.com/jetpack/guide). All of my repository function returns a NetworkBoundResource object. You can read more about this design implementation from the jetpack guide link, or view the example project from google here

In this particular problem, I'm trying to re-fetch information over the network when I pull down on the screen.

Current working implementation

Fragment listener (triggered when screen pulled down)

binding.refresh.setOnRefreshListener {
    profileViewModel.refreshUserProfile()
}

Then in my ViewModel I have a MutableLiveData that updates value on this function call

private val _refresh = MutableLiveData<Boolean>()

fun refreshUserProfile() {
    _refresh.value = true
}

And when _refresh.value changes, it triggers switchMap

val currentUserProfile: LiveData<Resource<UserProfile>> = _refresh.switchMap {
    if (it) {
        repository.getCurrentUserProfile(_username.value.toString())
    } else {
        AbsentLiveData.create()
    }
}

Repository function


fun getCurrentUserProfile(username: String): LiveData<Resource<UserProfile>> {
    return object : NetworkBoundResource<UserProfile, UserProfile>(AppExecutors.getInstance()) {
        override fun saveCallResult(item: UserProfile) {
            userProfileDao.update(item)
        }
        override fun shouldFetch(data: UserProfile?): Boolean {
            return true
        }
        override fun loadFromDb(): LiveData<UserProfile> {
            return userProfileDao.load(username)
        }
        override fun createCall(): LiveData<ApiResponse<UserProfile>> {
            return networkService.userProfileService.getUserProfileAsync(
                token,
                username
            )
        }
    }.asLiveData()
}

And then back at my fragment, I have an observer on this currentUserProfile ViewModel variable

profileViewModel.currentUserProfile.observe(viewLifecycleOwner, { userProfileResult ->
    when (userProfileResult.status) {...}
})

What I am trying to do

I would like to skip the step where I'm setting _refresh.value = true. And instead observe the repository function directly like this:

val currentUserProfile: LiveData<Resource<UserProfile>> = 
    repository.getCurrentUserProfile(_username.value.toString())

But this implementation will not trigger the observer in the fragment.

Question I don't quite understand why I wasn't able to trigger observer with my second implementation. And I'm also unsure if my initial implementation is even optimal or correct. I would appreciate any sort of feedback especially if you are familiar with this type of design.

leoybkim
  • 312
  • 4
  • 17

1 Answers1

0

I have had similar problems in the past & most of the time it was related to two things:

  1. dao instance to insert/update was not same as dao instance of observing the livedata.
  2. My livedata object was wrapped in some other livedata & returned. In short it wasn't the same livedata instance that dao returned.

You can log the instance & check if it's the same. It needs to be singleton. If you're using any kind of dependency injection tool (e.g Dagger) then checkout this: https://stackoverflow.com/a/44958478/9715339

My guess is that in your case it's most likely second case. As your livedata userProfileDao.load is being wrapped in NetworkBoundResource.asLiveData() & if you look at the code of NetworkBoundResource.result it's a MediatorLiveData. so you're not actively listening to the same live data being returned by userProfileDao.

Just for the sake of confirming this is the issue You can try listening to the direct livedata being returned from userProfileDao.load(username) . Create a method in your repository with & see.

You can try digging in that direction more.

Mayur Gajra
  • 8,285
  • 6
  • 25
  • 41
  • I'm not using any dependency injection tool. I know for sure that the room database is a singleton but I'm not sure if my DAO is one. I have since changed my implementation to use Flow instead of LiveData and I don't have any problems with observing the data anymore. So I want to rule out the DAO as being the problem. Thanks for replying. – leoybkim Jun 14 '21 at 07:02