如何在Kotlin中使用Livedata的MVVM模式从子片段访问父片段数据



我有一个列表片段,其中recyclerview用于显示列表,当使用按下列表项用户进入新片段(父片段)时,我使用viewpager2设置了一个带有2个片段(细节片段和第二片段)的tablayout。在这里,列表项的数据使用Bundle传递给父片段。我需要访问这是在父片段可用的数据,并使用它来显示数据在子片段(细节片段)

我使用柄作为依赖注入。

列出发送数据的片段代码

private val mylistsViewModel by viewModels<MyListsViewModel>()
private var mylists: MyListsResponse? = null
.......
`    private fun onItemClicked(mylistsResponse: MyListsResponse) {
val bundle = Bundle()
bundle.putString("mylist",Gson().toJson(mylistsResponse))
findNavController().navigate(R.id.action_mylistsFragment_to_parentFragment,bundle)
}`

在父片段中访问

private val mylistsViewModel by viewModels<MyListsViewModel>()
private var mylists: MyListsResponse? = null
.......
val jsonMyLists = arguments?.getString("mylist")
if (jsonMyLists != null) {
mylists = Gson().fromJson<MyListsResponse>(jsonMyLists, MyListsResponse::class.java)
mylists?.let {

}
}
<<p>

界面流/strong>从父段到子段访问数据

谁能建议一下如何解决这个问题?

我引用了这个googleDocs

并试图通过引用这段代码

来访问data in details片段
class ListFragment: Fragment() {
// Using the viewModels() Kotlin property delegate from the fragment-ktx
// artifact to retrieve the ViewModel
private val viewModel: ListViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.filteredList.observe(viewLifecycleOwner, Observer { list ->
// Update the list UI
}
}
}
class ChildFragment: Fragment() {
// Using the viewModels() Kotlin property delegate from the fragment-ktx
// artifact to retrieve the ViewModel using the parent fragment's scope
private val viewModel: ListViewModel by viewModels({requireParentFragment()})
...
}

但是当我进入detail fragment时,应用程序崩溃并给出错误

Fragment DetailsFragment不是子Fragment,它直接附加到ger. hill .android.internal.managers&;

问题是当您使用导航组件来处理应用程序中的导航时,requireParentFragment将返回NavHostFragment的实例,而不是您所期望的ListFragment。幸运的是,有一种方法可以使用导航组件backStackEntry和Hilt实例化视图模型,如下所示:

@AndroidEntryPoint
class ListFragment: Fragment() {
// Using the viewModels() Kotlin property delegate from the fragment-ktx
// artifact to retrieve the ViewModel
private val viewModel: ListViewModel by lazy {
val destination = findNavController().currentBackStackEntry!!.destination
val backStackEntry = findNavController().getBackStackEntry(destination.id)
val storeProducer: () -> ViewModelStore = {
backStackEntry.viewModelStore
}
createViewModelLazy(
ListViewModel::class, storeProducer,
factoryProducer = {
HiltViewModelFactory(requireActivity(), backStackEntry)
}
).value
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.filteredList.observe(viewLifecycleOwner, Observer { list ->
// Update the list UI
}
}
}
@AndroidEntryPoint
class ChildFragment: Fragment() {
// Using the viewModels() Kotlin property delegate from the fragment-ktx
// artifact to retrieve the ViewModel using the parent fragment's scope
private val viewModel: ListViewModel by lazy {
val destination = findNavController().previousBackStackEntry!!.destination
val backStackEntry = findNavController().getBackStackEntry(destination.id)
val storeProducer: () -> ViewModelStore = {
backStackEntry.viewModelStore
}
createViewModelLazy(
ListViewModel::class, storeProducer,
factoryProducer = {
HiltViewModelFactory(requireActivity(), backStackEntry)
}
).value
}
...
}

另外,不要忘记用@HiltViewModel注释ListViewModel

这种实现方式可以与任何片段和前一个一起工作,因为您可能会注意到在ChildFragment中,我们在ListFragment中使用previousBackStackEntry而不是currentBackStackEntry

最新更新