Machen Sie die Android-Ansichtsbindung mit Kotlin bequem

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 .


Bild


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 Bindinggenerierten 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)
        //   viewBinding
    }

    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)
        //   viewBinding
    }
}

, , . ?


, - ...


- View :


class ProfileFragment() : Fragment(R.layout.profile) {

    private val viewBinding: ProfileBinding by viewBinding()

    override fun onDestroyView() {
        super.onDestroyView()
        //  View  viewBinding
    }
}

, 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 }
        }
    }
}

.


All Articles