使用 Factory 创建一个共享的 ViewModel
Create a shared ViewModel with Factory
我有一个带有 3 个选项卡的 TabLayout 的 DocumentsFragment:
TabRulesFragment,
TabProceduresFragment,
TabGuidanceFragment
在 DocumentsFragment 中,我使用工厂初始化共享 viewModel DocumentsSharedViewModel:
class DocumentsFragment : Fragment() {
private lateinit var sharedViewModel: DocumentsSharedViewModel
private lateinit var viewPager2: ViewPager2
private lateinit var documentsCollectionAdapter: DocumentsCollectionAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val program = DocumentsFragmentArgs.fromBundle(requireArguments()).program
val name = DocumentsFragmentArgs.fromBundle(requireArguments()).name
val viewModelFactory = DocumentsSharedViewModelFactory(program, name)
sharedViewModel = ViewModelProvider(this, viewModelFactory)[DocumentsSharedViewModel::class.java]
在文档片段和 3 个选项卡片段之间共享数据。当我尝试连接到其中一个选项卡片段(例如 TabRulesFragment)中的共享 viewModel 时:
class TabRulesFragment : Fragment() {
private lateinit var tabRulesRecyclerView: RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val sharedViewModel : DocumentsSharedViewModel by viewModels()
val binding = TabRulesFragmentBinding.inflate(layoutInflater)
binding.viewModel = sharedViewModel
我收到无法创建 DocumentsSharedViewModel 实例的错误消息:
java.lang.RuntimeException: Cannot create an instance of class com.smellydogcoding.westvirginiaelectronicfieldguide.ui.documents.DocumentsSharedViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:188)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:238)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:169)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:44)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:31)
at com.smellydogcoding.westvirginiaelectronicfieldguide.ui.documents.rulesTab.TabRulesFragment.onCreateView$lambda-0(TabRulesFragment.kt:30)
at com.smellydogcoding.westvirginiaelectronicfieldguide.ui.documents.rulesTab.TabRulesFragment.onCreateView(TabRulesFragment.kt:32)
我假设 viewModelProvider 正在寻找工厂(它在 TabRulesFragment 中不存在,因为它在 DocumentsFragment 中)并在找不到时抛出错误。有没有什么方法可以在不创建共享数据模型的另一个实例的情况下使用来自共享数据模型的数据?
如果您想要将 ViewModel 的范围限定为您可以在片段之间共享的 Activity,您可以使用以下命令在两个片段中获取它。
val sharedModel: DocumentsSharedViewModel by activityViewModels()
根据 docs,其中有一个简单的示例,其中两个片段可以访问相同的 ViewModel
class ListFragment : Fragment() {
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//...
}
}
class DetailFragment : Fragment() {
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//...
}
}
正如评论中所指出的,如果您希望 ViewModel 保持在 parent fragment 范围内而不是使用 activity 范围,您可以使用它来在子片段中访问它
val sharedModel: DocumentsSharedViewModel by viewModels({ requireParentFragment() })
我有一个带有 3 个选项卡的 TabLayout 的 DocumentsFragment:
TabRulesFragment, TabProceduresFragment, TabGuidanceFragment
在 DocumentsFragment 中,我使用工厂初始化共享 viewModel DocumentsSharedViewModel:
class DocumentsFragment : Fragment() {
private lateinit var sharedViewModel: DocumentsSharedViewModel
private lateinit var viewPager2: ViewPager2
private lateinit var documentsCollectionAdapter: DocumentsCollectionAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val program = DocumentsFragmentArgs.fromBundle(requireArguments()).program
val name = DocumentsFragmentArgs.fromBundle(requireArguments()).name
val viewModelFactory = DocumentsSharedViewModelFactory(program, name)
sharedViewModel = ViewModelProvider(this, viewModelFactory)[DocumentsSharedViewModel::class.java]
在文档片段和 3 个选项卡片段之间共享数据。当我尝试连接到其中一个选项卡片段(例如 TabRulesFragment)中的共享 viewModel 时:
class TabRulesFragment : Fragment() {
private lateinit var tabRulesRecyclerView: RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val sharedViewModel : DocumentsSharedViewModel by viewModels()
val binding = TabRulesFragmentBinding.inflate(layoutInflater)
binding.viewModel = sharedViewModel
我收到无法创建 DocumentsSharedViewModel 实例的错误消息:
java.lang.RuntimeException: Cannot create an instance of class com.smellydogcoding.westvirginiaelectronicfieldguide.ui.documents.DocumentsSharedViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:188)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:238)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:169)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:44)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:31)
at com.smellydogcoding.westvirginiaelectronicfieldguide.ui.documents.rulesTab.TabRulesFragment.onCreateView$lambda-0(TabRulesFragment.kt:30)
at com.smellydogcoding.westvirginiaelectronicfieldguide.ui.documents.rulesTab.TabRulesFragment.onCreateView(TabRulesFragment.kt:32)
我假设 viewModelProvider 正在寻找工厂(它在 TabRulesFragment 中不存在,因为它在 DocumentsFragment 中)并在找不到时抛出错误。有没有什么方法可以在不创建共享数据模型的另一个实例的情况下使用来自共享数据模型的数据?
如果您想要将 ViewModel 的范围限定为您可以在片段之间共享的 Activity,您可以使用以下命令在两个片段中获取它。
val sharedModel: DocumentsSharedViewModel by activityViewModels()
根据 docs,其中有一个简单的示例,其中两个片段可以访问相同的 ViewModel
class ListFragment : Fragment() {
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//...
}
}
class DetailFragment : Fragment() {
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//...
}
}
正如评论中所指出的,如果您希望 ViewModel 保持在 parent fragment 范围内而不是使用 activity 范围,您可以使用它来在子片段中访问它
val sharedModel: DocumentsSharedViewModel by viewModels({ requireParentFragment() })