So i am migrating my code from Kotlin Synthetic
to ViewBinding
but when i write ViewBinding
code its so much boilerplate like the first assign all views as lateinit var
to use them in the whole class and then initialize these views in onViewCreated
so then i use by lazy
delegate to overcome that issue and everything work fines but when i try my app and it is single-activity-architecture
based so when i go from Afragment
to BFragment
and then come back to AFragment
some views like (toolbar not showing its title and drawer icons and menu) not inflated and i debug and realize that lazy delegate causing this because its giving first-time assigned value and also the variable is also immutable val
so i thought may be this causing the issue so i code custom mutable lazy delegate but this doesn't help either i don't know what i am doing please suggest anything.
MutableLazyDelegate.kt
class MutableLazyDelegate<T>(val initializer: () -> T) : ReadWriteProperty<Any?, T> {
private object UNINITIALIZED_VALUE
private var value: Any? = UNINITIALIZED_VALUE
@Suppress("UNCHECKED_CAST")
override fun getValue(thisRef: Any?, property: KProperty<*>): T =
if (value == UNINITIALIZED_VALUE)
synchronized(this) {
if (value == UNINITIALIZED_VALUE) initializer().also {
value = it
} else value as T
}
else value as T
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
synchronized(this) {
this.value = value
}
}
}
fun <T> mutableLazy(initializer: () -> T) = MutableLazyDelegate(initializer)
AFragment
class AFragment : Fragment(R.layout.a_fragment) {
private val binding by viewBinding(AFragmentBinding::bind)
private var toolbar by mutableLazy { binding.toolbar }
....
}
FragmentViewBindingDelegate
class FragmentViewBindingDelegate<T : ViewBinding>(
val fragment: Fragment,
val viewBindingFactory: (View) -> T
) : ReadOnlyProperty<Fragment, T> {
var binding: T? = null
init {
fragment.lifecycle.addObserver(object : DefaultLifecycleObserver {
val viewLifecycleOwnerLiveDataObserver =
Observer<LifecycleOwner?> {
val viewLifecycleOwner = it ?: return@Observer
viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
binding = null
}
})
}
override fun onCreate(owner: LifecycleOwner) {
fragment.viewLifecycleOwnerLiveData.observeForever(
viewLifecycleOwnerLiveDataObserver
)
}
override fun onDestroy(owner: LifecycleOwner) {
fragment.viewLifecycleOwnerLiveData.removeObserver(
viewLifecycleOwnerLiveDataObserver
)
}
})
}
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
val binding = binding
if (binding != null) return binding
val lifecycle = fragment.viewLifecycleOwner.lifecycle
if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
throw IllegalStateException("Should not attempt to get bindings when Fragment views are destroyed.")
}
return viewBindingFactory(thisRef.requireView()).also { this.binding = it }
}
}
fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> T) =
FragmentViewBindingDelegate(this, viewBindingFactory)