Why in Android binding examples Google uses val binding and var _binding?

Viewed 1640

The example is the following:

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
}

Why using a var _binding and a val binding, which simply gets _binding, and not using a lateinit var binding only? Is there something behind this choice?

Indeed, in the activity's example, they actually use a lateinit var:

private lateinit var binding: ResultProfileBinding

override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}

Why uselessly complicating that code?

2 Answers

It's naming convention where if you have private Kotlin properties then you should start it with an underscore.

Kotlin Docs:

Names for backing properties : If a class has two properties which are conceptually the same but one is part of a public API and another is an implementation detail, use an underscore as the prefix for the name of the private property:

class C {
    private val _elementList = mutableListOf<Element>()

    val elementList: List<Element>
         get() = _elementList
}

In the example that you provide, both variables are indeed private, but the concept of backing properties doesn't exlusively provide a public accessor to a private variable or member.

When implementing backing properties, the importance of the implementation is that the backing property is mutable, or var. The public accessor is typically immutable, const, or val.

The backing property can be changed, and so often times in designing a class we make a property private and provide a public accessor in order to ensure that it cannot be modified by anything other than the class's own methods/logic.

In the example you provided, both properties are private. This however doesn't mean that a lateinit var implementation would suffice, because whether the property can be initialized at declaration isn't the only issue to deal with.

_binding is var; mutable (non-const). _binding is val; immutable (const).

_binding is only valid between onCreate and onDestroy, and so must be the unsafe nullable type as it is in the example you provided (hence, var and ?).

binding provides an immutable (safe non-nullable) reference to the root of an inflated layout, which is then returned as the view reference.

lateinit var wouldn't work here to reference any of the views because it must be a var and as an unsafe nullable type would allow for a returned reference to be changed or null prior to referencing; this wouldn't satisfy the requirements of the method.

In your later example you see that a lateinit compiles and works,but semantically I don't think that is actually appropriate; For someone reading the code, using the first example provided, the circumstances are clear and a NullPointerException is guaranteed if the reference is null thanks to the unsafe nullable type (T?) conversion to a non-nullable type (T), !!:

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