جعل ربط Android View ملائمًا مع Kotlin

مرحبا! اسمي كيريل روزوف. أنا مؤلف قناة Telegram Android Broadcast . أنا أحب Kotlin كثيرًا وأحب استخدام ميزاته لتبسيط التطوير. لقد واجهت هذه المشكلة مؤخرًا عندما بدأوا في استخدام View Binding في مشروع Android جديد .


صورة


ظهرت هذه الميزة في Android Studio 3.6 ، ولكنها في الواقع ليست جديدة تمامًا ، ولكنها نسخة خفيفة الوزن من Android Data Binding . لماذا الكثير من المضاعفات؟ كانت المشكلة تكمن في السرعة - حيث تم استخدام العديد من المطورين Android Data Bindingفقط لإنشاء تعليمات برمجية بروابط عرض وتجاهل ميزات المكتبة الأخرى. لتسريع إنشاء رمز ، تم إنشاؤه View Binding. ومع ذلك ، فإن الطريقة القياسية للعمل معها هي تكرار التعليمات البرمجية التي تريد التخلص منها.


الطريقة القياسية للعمل مع View Binding


دعونا نلقي نظرة على عرض الربط باستخدام مثال التجزئة. لدينا مورد تخطيط باسم profile.xml(محتوياته لا تهم). إذا أردنا استخدام ViewBinding ، فسيبدو في الإصدار القياسي كما يلي:


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

هناك العديد من المشاكل هنا:


  • الكثير من التعليمات البرمجية الإضافية
  • : 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