Ilya
Ilya

Reputation: 33

Android Room - selective query with LiveData

Is it possible to get specific rows from Room with LiveData? My goal is to retrieve certain items from data base, when each item is conditioned by to columns ("page" and "category"). The problem is that in LiveData observer I always receive the same page - that livedata object had been initiated with it in the beginning. It has no effect if I change it afterwards in the ViewModel:

    private fun requestNextPageFromDB(page: Int) {
    filmsListLiveData = interactor.getPageOfFilmsFromDB(page)
}

I create the LiveData object in init block of my ViewModel:

var filmsListLiveData: LiveData<List<Film>>

init {
    filmsListLiveData = interactor.getPageOfFilmsFromDB(2)
    

The method in Interactor class I initiate the livedata object:

fun getPageOfFilmsFromDB(page: Int): LiveData<List<Film>> =
    repo.getPageOfFilmsInCategoryFromDB(page, getFilmsCategoryFromPreferences())

Next method in the repository:

fun getPageOfFilmsInCategoryFromDB(page: Int, category: String): LiveData<List<Film>> {
    return filmDao.getCachedFilmsByPageAndCategory(page, category)
}

And the last one in the Dao Intertface:

@Query("SELECT * FROM cached_films WHERE page=:requestedPage AND category=:requestedCategory")
fun getCachedFilmsByPageAndCategory(requestedPage: Int, requestedCategory:String): LiveData<List<Film>>

All the methods above are invoked properly when the page number changes in livedata object.

Thanks a lot in advance.

Upvotes: 2

Views: 291

Answers (1)

Ma3x
Ma3x

Reputation: 6589

From the description it seems that you are just replacing the filmsListLiveData reference, however the observer remains the original one, that is why it is not notified about any changes, since in the original filmsListLiveData there have been no changes.

You can use a MutableLiveData for the page value and then a Transformations.switchMap to obtain a LiveData that will react to the changes of the page value.

Inside your ViewModel, you can do something like this

    // starting page is 2, not sure if it should be 1 or 2, I just copied you logic from init
    private val currentPageLiveData = MutableLiveData(2) 
    var filmsListLiveData = Transformations.switchMap(currentPageLiveData) { page ->
        interactor.getPageOfFilmsFromDB(page)
    }

    private fun requestNextPageFromDB(page: Int) {
        currentPageLiveData.value = page
    }

    init {
        // not needed anymore - remove this code
        // filmsListLiveData = interactor.getPageOfFilmsFromDB(2)
    }

With that, every time requestNextPageFromDB(page: Int) will be called, currentPageLiveData value will change, the switchMap will get called and a new call to interactor.getPageOfFilmsFromDB(page) will be made. That will update the LiveData value and your observer will be called again.

So the switchMap does exactly what you need, it switches the LiveData behind the scenes every time the source LiveData changes (in this case the currentPageLiveData) in such a way, that existing observers stop observing the old LiveData instance, the one switched from, and start observing the new LiveData instance, the one switched to.

At this point you can also change var filmsListLiveData to val filmsListLiveData and remove all code that is trying to replace its reference, since there is no need to replace this LiveData anymore (now it reacts to the page value change on its own).

Upvotes: 1

Related Questions