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)
The solution in your case is to ditch the mutableLazy delegate and instead use an accessor
private val toolbar: Toolbar get() = binding.toolbar
Although in most cases, I'd recommend grabbing the toolbar from the binding variable that is assigned to a val
in the method where you're using it
override fun onViewCreated(...) {
super onViewCreated(...)
val binding = binding
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.