Hallo! Ich heiße Kirill Rozov. Ich bin der Autor des Telegrammkanals Android Broadcast . Ich liebe Kotlin sehr und ich mag es, seine Funktionen zu nutzen, um die Entwicklung zu vereinfachen. Ich war kürzlich mit diesem Problem konfrontiert, als sie anfingen, View Binding für ein neues Android-Projekt zu verwenden .

Diese Funktion wurde in Android Studio 3.6 veröffentlicht, ist jedoch nicht ganz neu, sondern eine leichtgewichtige Version von Android Data Binding . Warum so viele Komplikationen? Das Problem war die Geschwindigkeit - viele Entwickler Android Data Binding
generierten nur Code mit Links zu View und ignorierten andere Bibliotheksfunktionen. Um die Codegenerierung zu beschleunigen, erstellt View Binding
. Die Standardmethode für die Arbeit besteht jedoch darin, Code zu duplizieren, den Sie entfernen möchten.
Die Standardmethode für die Arbeit mit der Ansichtsbindung
Schauen wir uns die Ansichtsbindung am Beispiel Fragment an. Wir haben eine Layoutressource mit einem Namen profile.xml
(deren Inhalt keine Rolle spielt). Wenn wir ViewBinding verwenden möchten, sieht es in der Standardversion folgendermaßen aus:
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
}
}
Hier gibt es mehrere Probleme:
- Viel zusätzlicher Code
- : 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 }
}
}
}
.