0

I was going through developer docs for Data binding. I found the following snippet:

private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

Can anyone let me know the principle and advantage of using two variables for binding which are used in same fragment?

keshav kowshik
  • 2,354
  • 4
  • 22
  • 45

3 Answers3

4

At first glance, it seems like lateinit would be a more natural choice. However, the Fragment instance is still usable after onDestroyView since Fragment instances can be torn down and reattached later. lateinit won't let you change the parameter back into uninitialized state, so it's not suitable for this purpose.

Using !! can result in Kotlin NPEs, which is not great. I would suggest modifying the sample code to provide better documentation and error reporting, like this:

/** This property is only valid between onCreateView and onDestroyView. */
private val binding get() = _binding ?: 
    error("Binding is only valid between onCreateView and onDestroyView.")

But practically, your Fragment is not going to be so complicated that you would have trouble tracking down an error like this anyway.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
1

binding is a non-null property with nullable backing field, so when you access it you don't have to constantly use ? to check for nullability.

It will however throw KotlinNullPointerException if accessed when it's not valid as described by the comment.

Pawel
  • 15,548
  • 3
  • 36
  • 36
1

EDIT
this solution will cause a memory leak, as pointed out by IR42, and here is why

ORIGINAL ANSWER
null safety, but I think using lateinit is a better solution for that purpose

private lateinit var binding : ResultProfileBinding
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    binding = ResultProfileBinding.inflate(inflater, container, false)
    return binding.root
}
Stachu
  • 1,614
  • 1
  • 5
  • 17
  • even I felt lateint would be better – keshav kowshik Aug 18 '20 at 13:24
  • @Keshav1234 you should release `_binding` property in `onDestroyView`, you can't do that with `lateinit` property – IR42 Aug 18 '20 at 13:38
  • @IR42 are you sure? in Google's [Sunflower app](https://github.com/android/sunflower/blob/master/app/src/main/java/com/google/samples/apps/sunflower/GardenFragment.kt) they don't release it, and it's supposed to be a best practice for Jetpack – Stachu Aug 18 '20 at 16:03
  • 1
    @Stachu and therefore they have a memory leak when you move from `GardenFragment` fragment to another `android.widget.FrameLayout instance ​ Leaking: YES (ObjectWatcher was watching this because com.google.samples.apps.sunflower.GardenFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks) and View detached and has parent)` https://github.com/android/sunflower/issues/628 – IR42 Aug 18 '20 at 16:28