Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
}
}
@fivunlm

This comment has been minimized.

Copy link

@fivunlm fivunlm commented Feb 26, 2020

Hi there, thanks for this, I've been trying to use it but I get an error at line 19

java.lang.IllegalArgumentException: invalid parameter type. Must be one and instanceof LifecycleOwner

Have you faced such situation?

@mpradzin

This comment has been minimized.

Copy link

@mpradzin 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

This comment has been minimized.

Copy link

@frel 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

This comment has been minimized.

Copy link

@marlonlom marlonlom commented Apr 7, 2020

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

This comment has been minimized.

Copy link

@frel frel commented Apr 7, 2020

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

@jamiesanson

This comment has been minimized.

Copy link
Owner Author

@jamiesanson jamiesanson commented Apr 7, 2020

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