what is effect of defining fields twice in kotlin?

Viewed 112

While exploring some repositories on GitHub I found some people define fields twice for example

private var _binding: FragmentBinding? = null
private val binding: FragmentBinding get() = _binding!!


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

why do some developers do this and why not just define the field once

private var binding: FragmentBinding? = null
4 Answers

In this particular context this is done to avoid any memory leaks. Fragments outlive their view,which means any reference to the view must be set to null when view is destroyed. so to take care of the memory leak the reference to the binding object is set to null in onDestroyView. in your case onDestroyView should look as

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

so this takes care of the memory leak issue, but now there is another problem, every time you use the _binding to access some view, you need to use (!!) non-null assertion as _binding!!.myView.setOnClickListener etc.

In order to avoid this redundant use of (!!), there is another property binding, which is not null. so now you can simply write binding.myView.setOnClickListener.

The comments and other answer talking about you missing the concept are talking about a different concept than what you are asking about in your example code.

The concept they're talking about is using a more restrictive publicly exposed version of a property. Like making the public version of a MutableList exposed only as a read-only List. This is a good practice for encapsulation, but it is not what your example code is doing, although both involve using a backing property with an _ prefix.

Your example is with two private properties with the same type. This is done for Android view binding in a Fragment because it needs to be possible to set the property to null when the Fragment is detached, so the bound views are not leaked. But it is inconvenient to have to keep dealing with a nullable property in the Fragment code, since most of your uses of the binding will be in functions that are only called while the Fragment is attached and the binding reference is not null.

This code allows a backing nullable _binding property that stores the actual reference to the binding and can be set to null when the fragment is detached. The binding property has no backing field, so it cannot cause the views to be leaked, but you can use it as a non-null property, which is safe so long as you only call it while the Fragment is attached. It is similar to requireContext() and requireActivity(), which are conveniently non-null, but are only safe to use while the Fragment is attached.

I think you misunderstood the concept here!

It's paradigm in general programming that keep one private member field with the _ prefix while exposing another variable with the same name as public member of the class without _ prefix.


I.e. let's say you have an interface or an abstract class called "Foo" and it's inheritance/child class as "Bar".

interface Foo {}

class Bar : Foo

While using it's functionality into some other class (let's say 'Baz') you found out that creating object of "Bar" is good enough for you on this particular "Baz" class.

class Baz {
   var bar: Bar? = null
}

But, at the same time you also want your caller/consumer of "Baz" class not to have access to this var bar: Bar? = null in such a way that it's immutable since it's internal variable used on "Baz".

This is the moment, where this paradigm comes into picture where you expose your bar as read only variable while reassigning/modifying it internally n number of times as well as of the type of it's parent to limit it's scope. something like below:

class Baz {
    private var _bar: Bar? = null
    val bar: Foo get() = _bar // Here we expose private variable _bar as Foo type only on getter as well
}

Side note: (This happens in Kotlin, because it provides default getters & setters and providing getter only on public one restricts it's usage to read-only outside the class/object)

Source - Kotlin Docs

These are called backing properties in kotlin.

Advantages of using a backing properties.

  1. The variable with prefix _ will be private var.
    var - So it is mutable.
    private - So it can only be mutated in the same class, but it is not exposed to other files.

  2. The other variable will be public val.
    public - So it is accessible from any file.
    val - It can only be read. Writing to val is restricted.

  3. If the data has to changes from other classes, we can use a public method to do so. The advantages of using a method rather than the default constructor is we can add any custom validation logic we want before updating the private variable.

Related