Hilt-Dagger 从 Fragment 调用 ViewModel
Hilt-Dagger ViewModel calling from Fragment
我正在使用 ViewModel
更新操作栏中的标题
SharedViewModel
class SharedViewModel @ViewModelInject constructor(
@Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val title: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
val backButton: MutableLiveData<Boolean> by lazy {
MutableLiveData<Boolean>()
}
}
MainActivity 观察者
@AndroidEntryPoint
...
sharedViewModel.title.observe(this, Observer {
supportActionBar?.title = it
})
使用下面的代码似乎在 Fragment
中创建了一个新实例(已在调试器中检查):
@AndroidEntryPoint
...
private val viewModel: SharedViewModel by viewModels()
但似乎是这样工作的
val viewModel = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
这是应该这样做还是我做错了什么?
谢谢!
如果您想在片段中使用共享视图模型,则必须使用 by activityViewModels()
而不是 by viewModels()
。
为什么下一行可以,而 by viewModels()
不行?
ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
因为默认情况下 viewModels()
的 ownerProducer
参数值为 { this }
。为了更好地理解它,这里是源代码:
@MainThread
inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
如您所见,它是 Fragment
class 的扩展函数。这意味着 ViewModelStoreOwner
是 片段 。一旦片段从堆栈中移除,它存储在视图模型存储中的所有视图模型都消失了。
但是如果您使用 by activityViewModels()
,您将使用 Activity
作为视图模型商店所有者。注意使用 requireActivity().viewModelStore
而不是 ownerProducer().viewModelStore
默认情况下是 Fragment
。
@MainThread
inline fun <reified VM : ViewModel> Fragment.activityViewModels(
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },
factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })
最终,createViewModelLazy
正在调用
ViewModelProvider(store, factory).get(viewModelClass.java)
这相当于您使用
手动创建视图模型
ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
如何解决这个问题?
使用by activityViewModels()
:
@AndroidEntryPoint
...
private val viewModel: SharedViewModel by activityViewModels()
注意:by activityViewModels()
和 by viewModels()
只是 ViewModelProvider(...).get(...)
.
的延迟加载实现
我正在使用 ViewModel
更新操作栏中的标题
SharedViewModel
class SharedViewModel @ViewModelInject constructor(
@Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val title: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
val backButton: MutableLiveData<Boolean> by lazy {
MutableLiveData<Boolean>()
}
}
MainActivity 观察者
@AndroidEntryPoint
...
sharedViewModel.title.observe(this, Observer {
supportActionBar?.title = it
})
使用下面的代码似乎在 Fragment
中创建了一个新实例(已在调试器中检查):
@AndroidEntryPoint
...
private val viewModel: SharedViewModel by viewModels()
但似乎是这样工作的
val viewModel = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
这是应该这样做还是我做错了什么?
谢谢!
如果您想在片段中使用共享视图模型,则必须使用 by activityViewModels()
而不是 by viewModels()
。
为什么下一行可以,而 by viewModels()
不行?
ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
因为默认情况下 viewModels()
的 ownerProducer
参数值为 { this }
。为了更好地理解它,这里是源代码:
@MainThread
inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
如您所见,它是 Fragment
class 的扩展函数。这意味着 ViewModelStoreOwner
是 片段 。一旦片段从堆栈中移除,它存储在视图模型存储中的所有视图模型都消失了。
但是如果您使用 by activityViewModels()
,您将使用 Activity
作为视图模型商店所有者。注意使用 requireActivity().viewModelStore
而不是 ownerProducer().viewModelStore
默认情况下是 Fragment
。
@MainThread
inline fun <reified VM : ViewModel> Fragment.activityViewModels(
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },
factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })
最终,createViewModelLazy
正在调用
ViewModelProvider(store, factory).get(viewModelClass.java)
这相当于您使用
手动创建视图模型ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
如何解决这个问题?
使用by activityViewModels()
:
@AndroidEntryPoint
...
private val viewModel: SharedViewModel by activityViewModels()
注意:by activityViewModels()
和 by viewModels()
只是 ViewModelProvider(...).get(...)
.