91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android開發Viewbinding委托怎么實現

發布時間:2022-06-22 09:31:37 來源:億速云 閱讀:206 作者:iii 欄目:開發技術

本篇內容介紹了“Android開發Viewbinding委托怎么實現”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    從Crash到有意思的源碼

    委托模式是軟件設計模式中的一項基本技巧。在委托模式中,有兩個對象參與處理同一個請求,接受請求的對象將請求委托給另一個對象來處理。

    Kotlin 直接支持委托模式,更加優雅,簡潔。Kotlin 通過關鍵字 by 實現委托。

    上述是kotlin對于委托的釋義,Viewbinding委托就是把生成Viewbinding實例的過程交給委托類去完成,然后讓使用方可以忽略掉其中的細節,是一種非常好玩的模式了。

    但是由于Viewbinding的特殊性,它其實就會和當前的lifecycle綁定在一起。因為我們要在銷毀的情況下把實例重置為空。否則當我們頁面重新生成的情況下,就會出現view并不是當前的頁面的困擾。

    作者在定義的時候就將Viewbinding委托獲取的實例定義為了非空,這里我和我的同事其實是存在一些分歧的,我認為非空其實挺合理的,但是對方并不認為。

    恰巧這種空非空的問題,在實際的使用中就出現了很多不可預期的crash問題。比如說在一個異步操作中獲取viewbinding實例然后進行賦值操作,就會出現空指針異常。另外由于使用的是lifecycle的頁面銷毀方法,如果我們復寫了銷毀方法之后在設置這個值,也會出現崩潰問題。

    上述問題我在幾個我之前參考的庫中其實都發現了對應的問題。我參考了Binding,還有之前彭旭說的那個也有類似的情況。

    另外在fragment中,其實問題尤其的明顯。因為我們很多時候使用的fragment相關的LifecycleOwner是fragment本身,但是Android官方其實推薦我們使用的是fragment內部的view相關的LifecycleOwner。因為fragment相比較于activity,存在的問題就是多了幾個生命周期,比如createView,和onDestroyView。其中出現最多問題的也就是onDestroyView和onDestroy。

    有趣的代碼

    接下來我們看下這個作者是如何解決這些奇奇怪怪的問題的哦。

    private class FragmentViewBindingProperty<in F : Fragment, out T : ViewBinding>(
        private val viewNeedInitialization: Boolean,
        viewBinder: (F) -> T,
        onViewDestroyed: (T) -> Unit,
    ) : LifecycleViewBindingProperty<F, T>(viewBinder, onViewDestroyed) {
        private var fragmentLifecycleCallbacks: FragmentManager.FragmentLifecycleCallbacks? = null
        private var fragmentManager: Reference<FragmentManager>? = null
        // 賦值操作
        override fun getValue(thisRef: F, property: KProperty<*>): T {
            val viewBinding = super.getValue(thisRef, property)
            registerFragmentLifecycleCallbacksIfNeeded(thisRef)
            return viewBinding
        }
        private fun registerFragmentLifecycleCallbacksIfNeeded(fragment: Fragment) {
            if (fragmentLifecycleCallbacks != null) return
            val fragmentManager = fragment.parentFragmentManager.also { fm ->
                this.fragmentManager = WeakReference(fm)
            }
            fragmentLifecycleCallbacks = ClearOnDestroy(fragment).also { callbacks ->
                fragmentManager.registerFragmentLifecycleCallbacks(callbacks, false)
            }
        }
        override fun isViewInitialized(thisRef: F): Boolean {
            if (!viewNeedInitialization) return true
            if (thisRef !is DialogFragment) {
                return thisRef.view != null
            } else {
                return super.isViewInitialized(thisRef)
            }
        }
        override fun clear() {
            super.clear()
            fragmentManager?.get()?.let { fragmentManager ->
                fragmentLifecycleCallbacks?.let(fragmentManager::unregisterFragmentLifecycleCallbacks)
            }
            fragmentManager = null
            fragmentLifecycleCallbacks = null
        }
        override fun getLifecycleOwner(thisRef: F): LifecycleOwner {
            try {
                return thisRef.viewLifecycleOwner
            } catch (ignored: IllegalStateException) {
                error("Fragment doesn't have view associated with it or the view has been destroyed")
            }
        }
        // 有意思的代碼
        private inner class ClearOnDestroy(
            fragment: Fragment
        ) : FragmentManager.FragmentLifecycleCallbacks() {
            private var fragment: Reference<Fragment> = WeakReference(fragment)
            override fun onFragmentDestroyed(fm: FragmentManager, f: Fragment) {
                // Fix for destroying view for case with issue of navigation
                if (fragment.get() === f) {
                    postClear()
                }
            }
        }
    }

    從上述代碼上我們可以看出來,其中獲取的LifecycleOwner就是我上文說的viewLifecycleOwner。這個就其實已經非常精彩了。

    另外我們可以看下他在內部定義了ClearOnDestroy這個類,然后當onFragmentDestroyed觸發的時候調用postClear方法。而這個方法就是解決當我們在Destroyed中還執行了ViewBinding內的對象的操作的空指針問題。

    經典面試題的真實使用場景,Handler.post執行。很多人覺得Handler相關的面試題都是八股文,這次我們就通過這個真是場景來給大家說說這個有意思的問題。

    首先從onFragmentDestroyed方法會執行在Fragment本身的onDestroyView之前,原來我們會在這個方法下執行引用清空的操作。然后當onDestroyView執行的時候就會出現空指針異常了。那么Lifecycle有沒有提供一個在onDestroyView之后的方法呢?我們是不是可以考慮自己造一個呢?面試中,我們知道所有生命周期方法都是有主線程Handler來負責調度的,這也就是說活我么可以把生命周期方法認為就是一個Message,當onFragmentDestroyed執行的時候,onDestroyView也已經被添加到主線程的MessageQueue中,這個時候我們在post一個runnable,那么他的排序規則上來說,就必然在onDestroyView之后了。

    另外一些有意思的地方

    這個庫另外一個優點就是他同時支持反射和非反射的寫法。同時也支持了Activity,Fragment,View,FragmentDialog,ViewHolder等等。反射寫法是基于非反射寫法的,所以也保證了底層庫的一致性。

        //非反射寫法
        private val viewBinding by viewBinding(ViewProfileBinding::bind)
        //反射寫法
        private val viewBinding: ItemProfileBinding by viewBinding()

    同時他的反射相關的混淆配置文件也非常有意思。

    allowoptimization 指定對象可能會被優化,即使他們被keep選項保留。所指定對象可能會被改變(優化步驟),但可能不會被混淆或者刪除。該修飾符只對實現異常要求有用。

    -keep,allowoptimization class * implements androidx.viewbinding.ViewBinding {
        public static *** bind(android.view.View);
        public static *** inflate(...);
    }

    它只會keep實現了ViewBinding的類的bind和inflate方法。因為ViewBinding會將所有的xml轉化成一個類實例,如果不刪除掉沒有實際被調用的類的情況下就會導致dex包變大,大家對于包體積優化都是有追求的嗎。然后用了-keep,allowoptimization,這樣在混淆的代碼優化過程中就可以刪除掉沒有被調用的ViewBinding類了。

    “Android開發Viewbinding委托怎么實現”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    连州市| 清水河县| 金平| 婺源县| 永吉县| 赤水市| 濮阳市| 陈巴尔虎旗| 昌平区| 宁津县| 潼南县| 比如县| 黑龙江省| 共和县| 科技| 娱乐| 定结县| 马山县| 志丹县| 兖州市| 尼木县| 津市市| 天长市| 内丘县| 阿克陶县| 靖宇县| 云龙县| 读书| 威海市| 涟源市| 洪泽县| 贵南县| 益阳市| 德庆县| 汽车| 中超| 新疆| 阿荣旗| 普格县| 阳江市| 林周县|