13

I was left with some questions regarding ViewModels after reading this:

https://developer.android.com/topic/libraries/architecture/saving-states

It says here that you should use a combination of both a ViewModel for configuration changes (like screen rotation), and using onSaveInstanceState() for all other cases where an activity is destroyed and then recreated in order to save the UI state.

My question is how do we know the way to restore the state when onCreate(Bundle) is called - should I use the ViewModel or should I use the bundle received as a parameter? When the configuration changes, onSaveInstanceState() is also called, and obviously onCreate() is always called.

If I only restore the state from a ViewModel, it won't always remain with the correct data (since the activity could have been destroyed due to other reasons than configuration changes). If I only use the bundle I save in onSaveInstanceState() then why would I use a ViewModel to begin with?

CodeMonkey
  • 11,196
  • 30
  • 112
  • 203

1 Answers1

11

I think it's good to think of this sources as a chain. You have 2 sources of data - ViewModel, that is faster but lives less and saved instance state that is slower but lives longer.

The rule is simple - try using your ViewModel and if it is not populated use the bundle from onSaveInstanceState().

When you do val model = ViewModelProviders.of(this).get(MyViewModel::class.java) in onCreate() you can check if you get a new instance of viewModel. Then, if it is a new instance (i.e. it's data fields are empty) you can get some basic data from your bundle, like content id, and fetch data from the backend or database based on that id, populate your new ViewModel with it and then populate your activity from the ViewModel (if you are using LiveData it will be very natural).

Next time onCreate is called you repeat the process, either populating your activity from ViewModel or populating your ViewModel using data in the Bundle and then populating your activity from your ViewModel.

Update: Actually there is very similar approach described in the official docs. The only difference is that you pass the bundle to ViewModel and it decides if it needs fetching data, I was not specific about this mechanism.

TpoM6oH
  • 8,385
  • 3
  • 40
  • 72
  • What if for example all I have in the ViewModel are just primitives who are initialized to a default value? I won't be able to tell if it's because the instance is a new one, or if those are simply the correct values.. Anyway, in general your suggestion sounds like a workaround.. – CodeMonkey Feb 28 '19 at 18:24
  • Well, in this specific case you'll need to implement some field that will indicate that your ViewModel is not newly created one or add some data to your state bundle and use it. If you have just a bunch of primitives to save you won't get much from using ViewModel, in this case just implement instance state and use it. ViewModel helps you to retain complex downloaded data or user generated data. – TpoM6oH Feb 28 '19 at 18:45
  • Also check the answer update, it links to the official approach. – TpoM6oH Feb 28 '19 at 18:46
  • So from what I understand, it also just says you should check if the needed data is already there.. isn't there some sort of a system flag which tells you the reason you are in the onCreate? Or maybe a flag telling you if the ViewModel was just now created or not? – CodeMonkey Mar 01 '19 at 00:06
  • I think the framework calls no arguments constructor on the ViewModel when you first create it with ViewModelProviders, so you can use that as an indicator that the ViewModel is new. – TpoM6oH Mar 01 '19 at 10:14
  • There is also "SavedStateHandle" : https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-savedstate . What is it exactly? Does it work exactly like onSaveInstanceState of Fragment/Activity ? Will it restore the data after the app was stopped, meaning more than the life of a ViewModel? – android developer Mar 04 '23 at 10:23