Skip to content

Instantly share code, notes, and snippets.

@jamiesanson
Last active April 18, 2023 11:25
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jamiesanson/d1a3ed0910cd605e928572ce245bafc4 to your computer and use it in GitHub Desktop.
Save jamiesanson/d1a3ed0910cd605e928572ce245bafc4 to your computer and use it in GitHub Desktop.
Kotlin Property Delegate for Fragment view lifecycle binding
fun <T> Fragment.viewLifecycle(bindUntilEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY): ReadWriteProperty<Fragment, T> =
object: ReadWriteProperty<Fragment, T>, LifecycleObserver {
// 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@viewLifecycle
.viewLifecycleOwnerLiveData
.observe(this@viewLifecycle, Observer { newLifecycleOwner ->
viewLifecycleOwner
?.lifecycle
?.removeObserver(this)
viewLifecycleOwner = newLifecycleOwner.also {
it.lifecycle.addObserver(this)
}
})
}
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
fun onDestroy(event: Lifecycle.Event) {
if (event == bindUntilEvent) {
// Clear out backing property just before onDestroyView
binding = null
}
}
override fun getValue(
thisRef: Fragment,
property: KProperty<*>
): T {
// Return the backing property if it's set
return this.binding!!
}
override fun setValue(
thisRef: Fragment,
property: KProperty<*>,
value: T
) {
// Set the backing property
this.binding = value
}
}
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
this.property = value
}
}
@mpradzin
Copy link

mpradzin commented Mar 16, 2020

Any overwritten methods in the LifecycleObserver shouldn't have any arguments in it. Just adjust the onDestroy to the following and remove the default value (bindUntilEvent) in the method definition like this:

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy() {
        binding = null
    }

@frel
Copy link

frel commented Mar 18, 2020

Fyi, in the lifecycle docs there are comments on not using the lifecycle annotations

If you use Java 7 Language, Lifecycle events are observed using annotations. Once Java 8 Language becomes mainstream on Android, annotations will be deprecated, so between DefaultLifecycleObserver and annotations, you must always prefer DefaultLifecycleObserver.

https://developer.android.com/reference/kotlin/androidx/lifecycle/Lifecycle#init

This can easily be rewritten to use DefaultLifecycleObserver instead though.

@marlonlom
Copy link

It seems there is an error in this part:

 override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
        this.property = value
    }

i've removed it in my sample app and it works.

@frel
Copy link

frel commented Apr 7, 2020

In case anyone's interested, I refactored it to use DefaultLifecycleObserver https://gist.github.com/frel/5f3f928c27f4106ffd420a3d99c8037c

@jamiesanson
Copy link
Author

Apologies, I know this is incorrect and I've been meaning to update the blog post + gist. This is where I've settled - slightly more refined and reusable: https://gist.github.com/jamiesanson/478997780eb6ca93361df311058dc5c2

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