Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Should Child Fragments get referenced in the ViewModel or the Parent Fragment

I have the below layout

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

When I press a toggle button I need references to the childFragment so that I can show/hide each child fragment .beginTransaction().show(childFragmentB!!).hide(childFragmentA!!) instead of replacing them

I’m early in the Android world and I would like to know is it better to keep references to the child in the ViewModel or in the ParentFragment? Outside of the extra code are there any pros or cons to each?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

For example in the below Parent code when the children are initialized I use the properties from the Parent and eventually give each child a tag. When a device rotation occurs I check if the savedInstanceState & the tag are null or not to reinitialize them. From my understanding I can also use onSaveInstanceState (not included) to achieve the same thing but I can also use the properties inside the ViewModel because it isn’t affected by the rotation.

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
}

Parent:

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
   }
}

>Solution :

No, never use any references of Fragment/Activity ever in Viewmodel, mainly for two reasons

  1. The lifecycle of viewmodel is different to that of fragment meaning it reuses same instance of viewmodel on fragment being recreated due to config changes! In your case even if you hold the references in Viewmodel those references are dead objects and could potentially create leaks, as even the viewmodel is preserved the fragment/activity instances in foreground would be different than what you have preserved in viewmodel
  2. Unit testing and shared view model usage, it is always better to isolate the android framework out of viewmodel to better unit testing them in isolated environments.
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading