refactor: Simplify and optimize viewBinding delegate (#544)
Based on Christophe Beyl's technique described in https://bladecoder.medium.com/viewlifecyclelazy-and-other-ways-to-avoid-view-memory-leaks-in-android-fragments-4aa982e6e579
This commit is contained in:
parent
c2fc3d1f08
commit
4f9b283432
@ -21,16 +21,14 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import kotlin.properties.ReadOnlyProperty
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://medium.com/@Zhuinden/simple-one-liner-viewbinding-in-fragments-and-activities-with-kotlin-961430c6c07c
|
* https://bladecoder.medium.com/viewlifecyclelazy-and-other-ways-to-avoid-view-memory-leaks-in-android-fragments-4aa982e6e579
|
||||||
|
* by Christophe Beyls
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline fun <T : ViewBinding> AppCompatActivity.viewBinding(
|
inline fun <T : ViewBinding> AppCompatActivity.viewBinding(
|
||||||
@ -39,53 +37,32 @@ inline fun <T : ViewBinding> AppCompatActivity.viewBinding(
|
|||||||
bindingInflater(layoutInflater)
|
bindingInflater(layoutInflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
class FragmentViewBindingDelegate<T : ViewBinding>(
|
private class ViewLifecycleLazy<out T : Any>(
|
||||||
val fragment: Fragment,
|
private val fragment: Fragment,
|
||||||
val viewBindingFactory: (View) -> T,
|
private val viewBindingFactory: (View) -> T,
|
||||||
) : ReadOnlyProperty<Fragment, T> {
|
) : Lazy<T>, LifecycleEventObserver {
|
||||||
private var binding: T? = null
|
private var binding: T? = null
|
||||||
|
|
||||||
init {
|
override val value: T
|
||||||
fragment.lifecycle.addObserver(
|
get() {
|
||||||
object : DefaultLifecycleObserver {
|
return binding ?: run {
|
||||||
val viewLifecycleOwnerLiveDataObserver =
|
val newValue = viewBindingFactory(fragment.requireView())
|
||||||
Observer<LifecycleOwner?> {
|
binding = newValue
|
||||||
val viewLifecycleOwner = it ?: return@Observer
|
fragment.viewLifecycleOwner.lifecycle.addObserver(this)
|
||||||
|
newValue
|
||||||
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
|
override fun isInitialized() = binding != null
|
||||||
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 }
|
override fun toString() = binding.toString()
|
||||||
|
|
||||||
|
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||||
|
if (event == Lifecycle.Event.ON_DESTROY) {
|
||||||
|
binding = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> T) =
|
fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> T): Lazy<T> =
|
||||||
FragmentViewBindingDelegate(this, viewBindingFactory)
|
ViewLifecycleLazy(this, viewBindingFactory)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user