通过 kotlin lazy delegate 初始化和使用视图绑定视图,使视图在第一次膨胀后无法正确膨胀
initliaze and use viewbinding views by kotlin lazy delegate making view making view not inflate properly after first inflate
所以我正在将我的代码从 Kotlin Synthetic
迁移到 ViewBinding
,但是当我编写 ViewBinding
代码时,它的样板太多了,就像第一个将所有视图分配给 lateinit var
一样在整个 class 中使用它们,然后在 onViewCreated
中初始化这些视图,然后我使用 by lazy
委托来解决这个问题,一切正常,但是当我尝试我的应用程序时,它是 single-activity-architecture
基于所以当我从 Afragment
到 BFragment
然后回到 AFragment
一些视图(工具栏不显示其标题和抽屉图标和菜单)没有膨胀并且我调试并意识到导致此问题的惰性委托是因为它给出了 first-time 分配的值并且变量也是不可变的 val
所以我认为这可能是导致问题的原因所以我编写了自定义可变惰性委托但这不是帮助我不知道我在做什么请提出任何建议。
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)
您的解决方案是放弃 mutableLazy 委托,改用访问器
private val toolbar: Toolbar get() = binding.toolbar
尽管在大多数情况下,我建议从您使用它的方法中分配给 val
的绑定变量中获取工具栏
override fun onViewCreated(...) {
super onViewCreated(...)
val binding = binding
所以我正在将我的代码从 Kotlin Synthetic
迁移到 ViewBinding
,但是当我编写 ViewBinding
代码时,它的样板太多了,就像第一个将所有视图分配给 lateinit var
一样在整个 class 中使用它们,然后在 onViewCreated
中初始化这些视图,然后我使用 by lazy
委托来解决这个问题,一切正常,但是当我尝试我的应用程序时,它是 single-activity-architecture
基于所以当我从 Afragment
到 BFragment
然后回到 AFragment
一些视图(工具栏不显示其标题和抽屉图标和菜单)没有膨胀并且我调试并意识到导致此问题的惰性委托是因为它给出了 first-time 分配的值并且变量也是不可变的 val
所以我认为这可能是导致问题的原因所以我编写了自定义可变惰性委托但这不是帮助我不知道我在做什么请提出任何建议。
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)
您的解决方案是放弃 mutableLazy 委托,改用访问器
private val toolbar: Toolbar get() = binding.toolbar
尽管在大多数情况下,我建议从您使用它的方法中分配给 val
的绑定变量中获取工具栏
override fun onViewCreated(...) {
super onViewCreated(...)
val binding = binding