问题
Inside my Fragment
I initialize a ViewModel
using ViewModelProviders
.
I want it to take its Activity
if not null
, otherwise itself (Fragment
).
private val viewModel: MainViewModel by lazy {
ViewModelProviders.of(activity ?: this).get(MainViewModel::class.java)
}
None of the following functions can be called with the arguments supplied.
- of(Fragment) defined in androidx.lifecycle.ViewModelProviders
- of(FragmentActivity) defined in androidx.lifecycle.ViewModelPro
It seems the language does not allow me to invoke conflicting method signatures (between of(Activity)
and of(Fragment)
. (It might be understandable, maybe the compiler has to reference only one method and cannot link to both on the same line.) Is that so?
I now have to use
activity?.let {
ViewModelProviders.of(it).get(MainViewModel::class.java)
} ?: run {
ViewModelProviders.of(this).get(MainViewModel::class.java)
}
Is there any better way of doing this?
回答1:
Yes, it's compiler ambiguity, because you're passing activity
& this (fragment instance)
at the same time which has different implementations in ViewModelProviders
.
Another approach to do this is by using when
condition like below, (although your approach is also good):
private val viewModel: MainViewModel by lazy {
return@lazy when {
activity != null -> {
ViewModelProviders.of(activity as FragmentActivity).get(MainViewModel::class.java) // you can either pass activity object
}
else -> {
ViewModelProviders.of(this).get(MainViewModel::class.java) // or pass fragment object, both are not possible at same time.
}
}
}
回答2:
In addition to Jeel's answer, I'd recommend that if you commonly need to use this pattern, you should define an extension function on Fragment
for it to avoid repetition. For example:
fun Fragment.getViewModelProvider() =
activity?.let(ViewModelProviders::of) ?: ViewModelProviders.of(this)
inline fun <reified T : ViewModel> Fragment.getViewModel() =
getViewModelProvider().get(T::class.java)
From there, within any Fragment
you can just call either:
val viewModel: MainViewModel = getViewModel()
val viewModel = getViewModel<MainViewModel>()
It'll avoid both the boilerplate of fetching the provider as well as specifying the Java class specifically.
回答3:
if you are using androidx so should add two lines for lifecycle :
def lifecycle_version = "2.2.0-rc02"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
and use it like this :
val mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
来源:https://stackoverflow.com/questions/52811685/kotlin-does-not-understand-viewmodelproviders-ofactivity-fragment