GuilhE
GuilhE

Reputation: 11901

liveData with Coroutines and SavedStateHandle

This answer show us how can we use liveData in the repository to return a LiveData to ViewModel which the View will observe.
Now, what if we want to use SavedStateHandle? How can we transform the following code to use liveData{} from LiveData-Ktx?

ViewModel:

private val _itemLiveData = stateHandle.getLiveData<MyItem>(KEY, MyItem())
val itemLiveData: LiveData<MyItem> = _itemLiveData

suspend fun nextPage() {
    viewModelScope.launch {
        val item = repoCall...
        stateHandle.set(KEY, item)
    }
}

Activity:

viewModel.itemLiveData.observe(this, Observer {
    lifecycleScope.launch {/*...update ui...*/}
})

Will we benefit from using liveData{... emit()}?

I can see 3 advantages of using SavedStateHandle:
1 - Restore your viewModel state
2 - It calls .value() for us when we use stateHandle.set()
3 - stateHandle.getLiveData helps us initialize the value (this is also helpful with Data Binding for example)

Upvotes: 1

Views: 1916

Answers (2)

EpicPandaForce
EpicPandaForce

Reputation: 81578

Actually, with savedStateHandle, the get/set methods feel like a mistake to me. The only one that is truly reliable is getLiveData, which you can combine into other LiveData using Transformations.switchMap.

If you use getLiveData with a type that is supported by android.os.Bundle, then you get state persistence out of the box through it. If you don't, then you'll just get crashes. getLiveData already returns a MutableLiveData, which is why it is not a good idea to handle get/set manually, you can vall .value = on the MutableLiveData from SavedStateHandle if need be.

Upvotes: 1

Alexander Kazantsev
Alexander Kazantsev

Reputation: 26

I think you can do something like this

class SomeViewModel(
    private val savedStateHandle: SavedStateHandle
    repository:ItemsRepository) : ViewModel() {

    companion object {
        private const val PAGE_KEY = "page_key"
    }

    private val _page = MutableLiveData<PageId>(savedStateHandle.get(PAGE_KEY))

    private val _itemLiveData = Transformations.switchMap(_page) { pageId -> repository.getNextPage(pageId) }
    val itemLiveData: LiveData<MyItem> = _itemLiveData

    suspend fun nextPage(pageId: PageId) {
        _page.postValue(pageId)
    }

    override fun onCleared() {
        super.onCleared()
        savedStateHandle.set(PAGE_KEY, _page.value)
    }
}


class ItemsRespository {

    fun getNextPage(pageId:PageId) = liveData() {
        ....
        emit(someData)
    }
}

Let me know if it helped you. P.S. PageId it can be number of current page or other any page identifier

Upvotes: 0

Related Questions