问题
I need to use an AndroidViewModel
with application context and a SavedStateHandle
. I have it already working with application context, but I fail adding a SavedStateHandle
to it.
This is what I have, with only the application context:
// A1. get ViewModel in Fragment
val viewModel = ViewModelProvider(viewLifecycleOwner).get(MyViewModel::class.java)
// A2. MyViewModel derives from my custom BaseAndroidViewModel
class MyViewModel(application: Application) :BaseAndroidViewModel(application)
// A3. BaseAndroidViewModel in turn derives from AndroidViewModel
open class BaseAndroidViewModel(application: Application) : AndroidViewModel(application)
I assume for this question this could likely be reduced to:
// B1. get ViewModel in Fragment
val viewModel = ViewModelProvider(viewLifecycleOwner).get(MyViewModel::class.java)
// B2. BaseAndroidViewModel in turn derives from AndroidViewModel
class MyViewModel(application: Application) : AndroidViewModel(application)
So, for also having a SavedStateHandle
in MyViewModel
, how would I have to modify the call in the fragment (line B1
in the example code) ? Do I need an explicit call to the factory SavedStateViewModelFactory
? How exactly would that look like? (I am still new to Kotlin/Android, I've never worked with a factory before)
回答1:
EDIT: in the final release of AndroidX-Activity 1.2.0
and AndroidX-Fragment 1.1.0
, they made SavedStateViewModelFactory
the default factory in AppCompatActivity/Fragment, so it is not needed to override the default factory (which is what the second half of this answer does.)
Updating and then using
class MyViewModel(val savedStateHandle: SavedStateHandle): ViewModel()
class MyAndroidViewModel(application: Application, val savedStateHandle: SavedStateHandle): AndroidViewModel(application)
Should just work.
ORIGINAL:
how would I have to modify the call in the fragment (line B1 in the example code) ? Do I need an explicit call to the factory SavedStateViewModelFactory? How exactly would that look like?
In AndroidX-Activity 1.2.0, they added a new method called getDefaultViewModelProviderFactory()
:
+ @NonNull + @Override + public ViewModelProvider.Factory getDefaultViewModelProviderFactory() { + if (getApplication() == null) { + throw new IllegalStateException("Your activity is not yet attached to the " + + "Application instance. You can't request ViewModel before onCreate call."); + } + return ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()); + } +
Which means if I have a BaseActivity
or a BaseFragment
, I can swap this out for the SavedStateViewModelFactory
from viewmodel-savedstate
:
class BaseActivity: AppCompatActivity() {
override fun getDefaultViewModelProviderFactory(): ViewModelProvider.Factory =
SavedStateViewModelFactory(application, this, intent?.extras ?: Bundle())
}
class BaseFragment: Fragment() {
override fun getDefaultViewModelProviderFactory(): ViewModelProvider.Factory =
SavedStateViewModelFactory(requireActivity().application, this, arguments ?: Bundle())
}
Once you have that, you can rely on the automatic instantiation of ViewModel with SavedStateHandle
as one of their arguments:
class MyViewModel(val savedStateHandle: SavedStateHandle): ViewModel()
class MyAndroidViewModel(application: Application, val savedStateHandle: SavedStateHandle): AndroidViewModel(application)
Beware that the order application, savedStateHandle
is expected by SavedStateViewModelFactory
.
However, if you do need custom arguments on top of that, then you'd have to provide a object: AbstractSavedStateViewModelFactory
when you invoke the ViewModelProvider(viewModelStoreOwner).get(...)
method
来源:https://stackoverflow.com/questions/61063844/androidviewmodel-with-savedstate