Android Fragments 应该在ViewModel或ParentFragment中引用子片段吗

xggvc2p6  于 2023-06-06  发布在  Android
关注(0)|答案(1)|浏览(179)

我有下面的布局

-MainActivity
   -ParentFragment
      -MaterialButtonToggleGroup
      -ChildFragmentA
          -RecyclerView
      -ChildFragmentB
          -RecyclerView

当我按下切换按钮时,我需要引用childFragment,这样我就可以显示/隐藏每个子片段.beginTransaction().show(childFragmentB!!).hide(childFragmentA!!),而不是替换它们
我很早就进入Android世界,我想知道在ViewModel中还是在ParentFragment中保留对孩子的引用更好?除了额外的代码之外,每个代码都有优点或缺点吗?
例如,在下面的Parent代码中,当初始化子代码时,我使用Parent中的属性,并最终为每个子代码指定tag。当设备轮换发生时,我检查savedInstanceStatetag是否为空,以重新初始化它们。根据我的理解,我也可以使用onSaveInstanceState(不包括)来实现相同的功能,但我也可以使用ViewModel中的属性,因为它不受旋转的影响。
视图模型:

class MyViewModel: ViewModel() {

    private var mutableList = MutableLiveData<ArrayList<String>>()
    val recyclerViewList: LiveData<ArrayList<String>> get() mutableList

    fun addItemToMutableList(item: String) {
        mutableList.value?.add(item)
    }

    // If I use these instead of the properties inside the parent I won't need the checks and the tags 
    var childFragmentA: ChildFragmentA? = null
    var childFragmentB: ChildFragmentB? = null
}

家长:

class ParentFragment: Fragment() {

    // _binding ...
    // binding ...
    private lateinit var myViewModel: MyViewModel

    val childTagA = "childFragmentA"
    val childTagB = "childFragmentB"

    // Instead of using these would it be better to just use the properties inside the ViewModel
    var childFragmentA: ChildFragmentA? = null
    var childFragmentB: ChildFragmentB? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
      inflater: LayoutInflater, container: ViewGroup?,
      savedInstanceState: Bundle?
      ): View? {

       // _binding = initialize _binding ...

       if (savedInstanceState == null) {

           myViewModel = ViewModelProvider(requireActivity())[MyViewModel::class.java]
       }

       if (savedInstanceState == null && childFragmentManager.findFragmentByTag(childTagA) == null && childFragmentManager.findFragmentByTag(childTagB) == null)

           childFragmentA = ChildFragmentA() // Alternatively I can use myViewModel.childFragmentA = ChildFragmentA()
           childFragmentB = ChildFragmentB()

           childFragmentManager.beginTransaction()
                .add(binding.containerFrameLayout.id, childFragmentA!!, childTagA)
                .add(binding.containerFrameLayout.id, childFragmentB!!, childTagB)
                .hide(childFragmentB!!)
                .commit()

       } else {

           childFragmentA = childFragmentManager.findFragmentByTag(childTagA) as ChildFragmentA
           childFragmentB = childFragmentManager.findFragmentByTag(childTagB) as ChildFragmentB
       }

       return binding.root
   }
}
bvuwiixz

bvuwiixz1#

,永远不要在Viewmodel中使用Fragment/Activity的任何引用,主要有两个原因

  1. viewmodel的生命周期与fragment不同,这意味着它在fragment上重复使用viewmodel的同一个示例,因为配置更改而重新创建!在本例中,即使您在Viewmodel中保存引用,这些引用也是死对象,可能会造成泄漏,因为即使保留了viewmodel,前台的片段/活动示例也会与您在viewmodel中保留的不同。
    1.单元测试和共享视图模型的使用,最好将android框架从viewmodel中隔离出来,以便在隔离的环境中更好地进行单元测试。

相关问题