I am trying first handle the response from API by using observe. Later after observing the handled variable I want to save it to database.
The variable tokenFromApi is updated inside tokenResponseFromApi's observer. Is it possible to observe tokenFromApi outside the observer of tokenResponseFromApi? When debugged, the code did not enter inside tokenFromApi observer when the app started.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
var tokenResponseFromApi: LiveData<String>? = MutableLiveData<String>()
var tokenFromApi: LiveData<TokenEntity>? = MutableLiveData<TokenEntity>()
tokenResponseFromApi?.observe(viewLifecycleOwner, Observer {
tokenResponseFromApi ->
if (tokenResponseFromApi != null) {
tokenFromApi = viewModel.convertTokenResponseToEntity(tokenResponseFromApi, dh.asDate)
}
})
tokenFromApi?.observe(viewLifecycleOwner, Observer {
tokenFromApi ->
if (tokenFromApi != null) {
viewModel.saveTokenToDB(repo, tokenFromApi)
}
})
}
Your problem is that you're registering the observer on
tokenFromApiduring setup, and when you get your API response, you're replacingtokenFromApiwithout registering an observer on it. So if it ever emits a value, you'll never know about it. The only observer you have registered is the one on the discardedtokenFromApiwhich is never used by anythingHonestly your setup here isn't how you're supposed to use
LiveData. Instead of creating a whole newtokenFromApifor each response, you'd just have a singleLiveDatathat things can observe. When there's a new value (like an API token) you set that on theLiveData, and all the observers see it and react to it. Once that's wired up, it's done and it all works.The way you're doing it right now, you have a data source that needs to be taken apart, replaced with a new one, and then everything reconnected to it - every time there's a new piece of data, if you see what I mean.
Ideally the Fragment is the UI, so it reacts to events (by observing a data source like a
LiveDataand pushes UI events to the view model (someone clicked this thing, etc). That API fetching and DB storing really belongs in the VM - and you're already half doing that with those functions in the VM you're calling here, right? TheLiveDatas belong in the VM because they're a source of data about what's going on inside the VM, and the rest of the app - they expose info the UI needs to react to. Having theLiveDatainstances in your fragment and trying to wire them up when something happens is part of your problemHave a look at the App Architecture guide (that's the UI Layer page but it's worth being familiar with the rest), but this is a basic sketch of how I'd do it:
so it's basically all contained within the VM - the UI stuff like fragments doesn't need to know anything about API calls, whether something is being stored, how it's being stored. The VM can update one of its exposed
LiveDataobjects when it needs to emit some new data, update some state, or whatever - stuff that's interesting to things outside the VM, not its internal workings. The Fragment justobserves whichever one it's interested in, and updates the UI as required.(I know the callback situation might be more complex than that, like saving to the DB might involve a
Flowor something. But the idea is the same - in its callback/result function, push a value to yourLiveDataas appropriate so observers can receive it. And there's nothing wrong with usingLiveDataorFlowobjects inside the VM, and wiring those up so a newTokenEntitygets pushed to an observer that callssaveTokenToDb, if that kind of pipeline setup makes sense! But keep that stuff private if the outside world doesn't need to know about those intermediate steps