Last active
December 14, 2020 11:36
-
-
Save Frank1234/94211000cae3ec7652442bbc18172f25 to your computer and use it in GitHub Desktop.
Holds and manages ViewBinding inside a Fragment.
This file contains hidden or 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
/** | |
* Holds and manages ViewBinding inside a Fragment. | |
*/ | |
interface ViewBindingHolder<T : ViewBinding> { | |
val binding: T? | |
/** | |
* Saves the binding for cleanup on onDestroy, calls the specified function [onBound] with `this` value | |
* as its receiver and returns the bound view root. | |
*/ | |
fun initBinding(binding: T, fragment: Fragment, onBound: (T.() -> Unit)?): View | |
/** | |
* Calls the specified [block] with the binding as `this` value and returns the binding. As a consequence, this method | |
* can be used with a code block lambda in [block] or to initialize a variable with the return type. | |
* | |
* @throws IllegalStateException if not currently holding a ViewBinding (when called outside of an active fragment's lifecycle) | |
*/ | |
fun requireBinding(block: (T.() -> Unit)? = null): T | |
} | |
class ViewBindingHolderImpl<T : ViewBinding> : ViewBindingHolder<T>, LifecycleObserver { | |
override var binding: T? = null | |
var lifecycle: Lifecycle? = null | |
private lateinit var fragmentName: String | |
/** | |
* To not leak memory we nullify the binding when the view is destroyed. | |
*/ | |
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) | |
fun onDestroyView() { | |
lifecycle?.removeObserver(this) // not mandatory, but preferred | |
lifecycle = null | |
binding = null | |
} | |
override fun requireBinding(block: (T.() -> Unit)?) = | |
binding?.apply { block?.invoke(this) } ?: throw IllegalStateException("Accessing binding outside of Fragment lifecycle: $fragmentName") | |
override fun initBinding(binding: T, fragment: Fragment, onBound: (T.() -> Unit)?): View { | |
this.binding = binding | |
lifecycle = fragment.viewLifecycleOwner.lifecycle | |
lifecycle?.addObserver(this) | |
fragmentName = fragment::class.simpleName ?: "N/A" | |
onBound?.invoke(binding) | |
return binding.root | |
} | |
} |
Hey, when and how is the optional
onDestroyView
called ? Is it called automatically by the system when onDestroy() is triggerred ? In What sequence would this be getting called, when we have anonDestroyView
already overridden in our fragment?
It is called when onDestroyView is triggered (using onDestroy would be a memory leak). It is not optional btw.
It is called just before your own (Fragment's) onDestroyView, so you cannot access the binding anymore in your custom onDestroyView.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey, when and how is the optional
onDestroyView
called ? Is it called automatically by the system when onDestroy() is triggerred ? In What sequence would this be getting called, when we have anonDestroyView
already overridden in our fragment?