Membuat Android View Binding nyaman dengan Kotlin

Halo! Nama saya Kirill Rozov. Saya penulis saluran Telegram Android Broadcast . Saya sangat menyukai Kotlin dan saya suka menggunakan fitur-fiturnya untuk menyederhanakan pengembangan. Baru-baru ini saya menghadapi masalah ini ketika mereka mulai menggunakan View Binding pada proyek Android baru .


gambar


Fitur ini muncul di Android Studio 3.6, tetapi sebenarnya itu tidak sepenuhnya baru, tetapi versi ringan dari Android Data Binding . Kenapa banyak sekali komplikasi? Masalahnya adalah kecepatan - banyak pengembang Android Data Bindinghanya digunakan untuk menghasilkan kode dengan tautan ke Lihat dan mengabaikan fitur perpustakaan lainnya. Untuk mempercepat pembuatan kode, dibuat View Binding. Namun, cara standar untuk mengatasinya adalah dengan menggandakan kode yang ingin Anda singkirkan.


Cara standar untuk bekerja dengan View Binding


Mari kita lihat View Binding menggunakan contoh Fragment. Kami memiliki sumber daya tata letak dengan nama profile.xml(isinya tidak masalah). Jika kita ingin menggunakan ViewBinding, maka dalam versi standar akan terlihat seperti ini:


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

Ada beberapa masalah di sini:


  • Banyak kode tambahan
  • : 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