Last active
May 29, 2024 10:43
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!" | |
} | |
} |
For those who have a problem with importing DefaultLifecycleObserver
add this dependency:
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
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
Great idea.
I rewrote it, trying to simplify it a bit.
https://gist.github.com/rishabhkohli/d4a4e49049b0a3578cb4347191a78de5