Reputation: 12639
How to recreate ViewModel
that was created with params injected via Factory
after instance of activity is recreated?
ViewModel
has a constructor like this:
class MyViewModel(
val model: MyModel,
val repository: MyRepository
) : ViewModel()
I instantiate it with factory:
ViewModelProviders
.of(this, MyViewModelFactory(
model = MyModel()
repository = MyRepository()))
.get(MyViewModel::class.java)
I tried to recover ViewModel
like this, while savedInstanceState
is not null (activity is recreated):
ViewModelProviders
.of(this)
.get(MyViewModel::class.java)
This causes a crash because no 0 arguments constructor
is present inside MyViewModel
class.
As, for passing factory each time:
My problem with that is, that whatever I pass as a MyModel
to ViewModel
, and that comes from activity Intent
, might change later, due to user interaction. That would mean, when recreating, the MyModel
in the Intent is outdated to the model that is already stored in ViewModel
and was tampered by user interaction.
Upvotes: 1
Views: 1328
Reputation: 11754
This causes a crash because no 0 arguments constructor is present inside MyViewModel class.
It'll crash, as you're not passing any factory to construct the ViewModel
.
How to recreate ViewModel that was created with params injected via Factory after instance of activity is recreated?
AFAIK, you don't have to manually recreate the ViewModel
on savedInstanceState
. You may use viewModel
to store data that are used in the activity.So, on recreation of the activity, the ViewModelProvider
will not create a new instance of the viewModel
but will give you the old instance and the data held in the viewModel
will not be cleared.So there's no need to worry about savedInstanceState
.
TIP: If you want to manage the creation of the factory and improve the recreation process. you may check this article on ViewModel with Dagger
Upvotes: 2
Reputation: 12639
Probably the only answer is, that it cannot be done this way. If the factory was provided, it has to be provided at all time. I don't know mechanism underneath ViewModel
recreation but these are not as smart as I hoped.
My current implementation looks like this:
viewModel = ViewModelProviders
.of(this, MyFactory(MyRepository()))
.get(MyMViewModel::class.java)
val binding = DataBindingUtil.setContentView<ActivityCreateFoodstuffBinding>(this, R.layout.my_activity)
binding.viewModel = viewModel
if (savedInstanceState == null) {
val model = intent.getParcelableExtra<MyModel>("model")
viewModel.model.set(model)
}
I use one param constructor in ViewModel
that always takes repository, but model I moved away and set it only when the activity is freshly created.
Upvotes: 0
Reputation: 2560
There are no 0 argument constructors in MyViewModel
. When you try to get the instance of ViewModel without providing a Factory it will look for a 0 argument constructor.
You can use this regardless of whether savedInstanceState
is null
or not.
ViewModelProviders
.of(this, MyViewModelFactory(
model,repository))
.get(MyViewModel::class.java)
Rather how you create repository
and model
changes on the basis of savedInstanceState
value, depending on your use case or implementation.
Upvotes: 0