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)

Article reference

这是应该这样做还是我做错了什么?

谢谢!

如果您想在片段中使用共享视图模型,则必须使用 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(...).

的延迟加载实现