salut! Je m'appelle Kirill Rozov. Je suis l'auteur de la chaîne Telegram Android Broadcast . J'aime beaucoup Kotlin et j'aime utiliser ses fonctionnalités pour simplifier le développement. J'ai récemment rencontré ce problème lorsqu'ils ont commencé à utiliser View Binding sur un nouveau projet Android .

Cette fonctionnalité est apparue dans Android Studio 3.6, mais en fait elle n'est pas entièrement nouvelle, mais une version allégée d' Android Data Binding . Pourquoi tant de complications? Le problème était la vitesse - de nombreux développeurs utilisaient Android Data Binding
uniquement pour générer du code avec des liens vers View et ignoraient les autres fonctionnalités de la bibliothèque. Pour accélérer la génération de code, créé View Binding
. Cependant, la façon standard de travailler avec elle est de dupliquer le code dont vous voulez vous débarrasser.
La façon standard de travailler avec View Binding
Examinons la liaison de vues à l'aide de l'exemple Fragment. Nous avons une ressource de mise en page avec un nom profile.xml
(son contenu n'a pas d'importance). Si nous voulons utiliser ViewBinding, alors dans la version standard, cela ressemblera à ceci:
class ProfileFragment : Fragment(R.layout.profile) {
private var viewBinding: ProfileBinding? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding = ProfileBinding.bind(view)
}
override fun onDestroyView() {
super.onDestroyView()
viewBinding = null
}
}
Il y a plusieurs problèmes ici:
- Beaucoup de code supplémentaire
- : Fragment
- Property
viewBinding
nullable .
C Kotlin
Kotlin Delegated Property
property Kotlin . , ViewBinding
. , ViewBinding
:
class FragmentViewBindingProperty<T : ViewBinding>(
private val viewBinder: ViewBinder<T>
) : ReadOnlyProperty<Fragment, T> {
internal var viewBinding: T? = null
private val lifecycleObserver = BindingLifecycleObserver()
@MainThread
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
checkIsMainThread()
this.viewBinding?.let { return it }
val view = thisRef.requireView()
thisRef.viewLifecycleOwner.lifecycle.addObserver(lifecycleObserver)
return viewBinder.bind(view).also { vb -> this.viewBinding = vb }
}
private inner class BindingLifecycleObserver : DefaultLifecycleObserver {
@MainThread
override fun onDestroy(owner: LifecycleOwner) {
owner.lifecycle.removeObserver(this)
viewBinding = null
}
}
}
-, :
inline fun <reified T : ViewBinding> Fragment.viewBinding(): ReadOnlyProperty<Fragment, T> {
return FragmentViewBindingProperty(DefaultViewBinder(T::class.java))
}
:
class ProfileFragment() : Fragment(R.layout.profile) {
private val viewBinding: ProfileBinding by viewBinding()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
}
, , . ?
, - ...
- View :
class ProfileFragment() : Fragment(R.layout.profile) {
private val viewBinding: ProfileBinding by viewBinding()
override fun onDestroyView() {
super.onDestroyView()
}
}
, ViewBinding property . super.onDestroyView()
. Fragment.viewLifecycleOwner
.
ON_DESTROY
Fragment.viewLifecycleOwner
Fragment.onDestroyView()
, FragmentViewBindingProperty
, . . , Handler
:
class FragmentViewBindingProperty<T : ViewBinding>(...) : ReadOnlyProperty<Fragment, T> {
internal var viewBinding: T? = null
private inner class BindingLifecycleObserver : DefaultLifecycleObserver {
private val mainHandler = Handler(Looper.getMainLooper())
@MainThread
override fun onDestroy(owner: LifecycleOwner) {
owner.lifecycle.removeObserver(this)
mainHandler.post { viewBinding = null }
}
}
}
.