Lately I have become fond of initializing my view bindings lazily using requireView()
.
To elaborate, I tend to write this:
class ExampleFragment : Fragment() {
private val binding by lazy { FragmentExampleBinding.bind(requireView()) }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// make use of binding
}
}
... instead of this:
class ExampleFragment : Fragment() {
private lateinint var binding: FragmentExampleBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding = FragmentExampleBinding.bind(view)
// make use of binding
}
}
It feels to me a bit cleaner (although it just saves one or two lines). However, I haven't seen this being used anywhere, which makes come to the actual question: Is there something wrong with this approach? Is there anything I have overlooked?
Note: I can see that making use of binding
for the first time in ie. a coroutine might cause requireView()
to be called after the fragment has been killed (and thus throw an IllegalStateException
). It doesn't seem too concerning to me though, as all coroutines for the fragment should be called "under" its viewLifecycleOwner
and therefore shouldn't outlive it.
CodePudding user response:
Both of your examples technically leak your views when the Fragment's view is destroyed. If you don't care about that, your version of doing it is no worse than using lateinit
, aside from some insignificant overhead from the property delegate and Lazy's default thread-safety mode.
Some argue (see onDestroyView section) that it doesn't matter if you leak views from a Fragment, because the Fragment instance lives in a destroyed state only temporarily. For more information, see this question.
In practice, I never need to use the binding outside onViewCreated
anyway, so I just use a local variable instead of a property.