Skip to content

Instantly share code, notes, and snippets.

@jamiesanson
Last active May 29, 2024 10:43
Show Gist options
  • Save jamiesanson/478997780eb6ca93361df311058dc5c2 to your computer and use it in GitHub Desktop.
Save jamiesanson/478997780eb6ca93361df311058dc5c2 to your computer and use it in GitHub Desktop.
A Kotlin lazy implementation which automatically clears itself at appropriate times in the View Lifecycle, with a Fragment example
import androidx.fragment.app.Fragment
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
fun <T> Fragment.viewLifecycleLazy(initialise: () -> T): ReadOnlyProperty<Fragment, T> =
object : ReadOnlyProperty<Fragment, T>, DefaultLifecycleObserver {
// A backing property to hold our value
private var binding: T? = null
private var viewLifecycleOwner: LifecycleOwner? = null
init {
// Observe the View Lifecycle of the Fragment
this@viewLifecycleLazy
.viewLifecycleOwnerLiveData
.observe(this@viewLifecycleLazy, Observer { newLifecycleOwner ->
viewLifecycleOwner
?.lifecycle
?.removeObserver(this)
viewLifecycleOwner = newLifecycleOwner.also {
it.lifecycle.addObserver(this)
}
})
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
binding = null
}
override fun getValue(
thisRef: Fragment,
property: KProperty<*>
): T {
// Return the backing property if it's set, or initialise
return this.binding ?: initialise().also {
this.binding = it
}
}
}
class SomeFragment: Fragment(R.layout.some_fragment) {
val binding by viewLifecycleLazy { SomeFragmentBinding.bind(requireView()) }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.someTextView.text = "Hello View Binding!"
}
}
@gmk57
Copy link

gmk57 commented Jan 20, 2021

There is a catch: DefaultLifecycleObserver.onDestroy() is called before Fragment.onDestroyView(), so if you access binding from onDestroyView(), a new binding is created and cached. If later this fragment is restored from back stack, binding still points to that old view. We need to check current lifecycle state, see example here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment