您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Android開發(fā)Viewbinding委托怎么實(shí)現(xiàn)”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
委托模式是軟件設(shè)計(jì)模式中的一項(xiàng)基本技巧。在委托模式中,有兩個(gè)對(duì)象參與處理同一個(gè)請(qǐng)求,接受請(qǐng)求的對(duì)象將請(qǐng)求委托給另一個(gè)對(duì)象來處理。
Kotlin 直接支持委托模式,更加優(yōu)雅,簡潔。Kotlin 通過關(guān)鍵字 by 實(shí)現(xiàn)委托。
上述是kotlin對(duì)于委托的釋義,Viewbinding委托就是把生成Viewbinding實(shí)例的過程交給委托類去完成,然后讓使用方可以忽略掉其中的細(xì)節(jié),是一種非常好玩的模式了。
但是由于Viewbinding的特殊性,它其實(shí)就會(huì)和當(dāng)前的lifecycle綁定在一起。因?yàn)槲覀円阡N毀的情況下把實(shí)例重置為空。否則當(dāng)我們頁面重新生成的情況下,就會(huì)出現(xiàn)view并不是當(dāng)前的頁面的困擾。
作者在定義的時(shí)候就將Viewbinding委托獲取的實(shí)例定義為了非空,這里我和我的同事其實(shí)是存在一些分歧的,我認(rèn)為非空其實(shí)挺合理的,但是對(duì)方并不認(rèn)為。
恰巧這種空非空的問題,在實(shí)際的使用中就出現(xiàn)了很多不可預(yù)期的crash問題。比如說在一個(gè)異步操作中獲取viewbinding實(shí)例然后進(jìn)行賦值操作,就會(huì)出現(xiàn)空指針異常。另外由于使用的是lifecycle的頁面銷毀方法,如果我們復(fù)寫了銷毀方法之后在設(shè)置這個(gè)值,也會(huì)出現(xiàn)崩潰問題。
上述問題我在幾個(gè)我之前參考的庫中其實(shí)都發(fā)現(xiàn)了對(duì)應(yīng)的問題。我參考了Binding,還有之前彭旭說的那個(gè)也有類似的情況。
另外在fragment中,其實(shí)問題尤其的明顯。因?yàn)槲覀兒芏鄷r(shí)候使用的fragment相關(guān)的LifecycleOwner是fragment本身,但是Android官方其實(shí)推薦我們使用的是fragment內(nèi)部的view相關(guān)的LifecycleOwner。因?yàn)閒ragment相比較于activity,存在的問題就是多了幾個(gè)生命周期,比如createView,和onDestroyView。其中出現(xiàn)最多問題的也就是onDestroyView和onDestroy。
接下來我們看下這個(gè)作者是如何解決這些奇奇怪怪的問題的哦。
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。這個(gè)就其實(shí)已經(jīng)非常精彩了。
另外我們可以看下他在內(nèi)部定義了ClearOnDestroy這個(gè)類,然后當(dāng)onFragmentDestroyed觸發(fā)的時(shí)候調(diào)用postClear方法。而這個(gè)方法就是解決當(dāng)我們?cè)贒estroyed中還執(zhí)行了ViewBinding內(nèi)的對(duì)象的操作的空指針問題。
經(jīng)典面試題的真實(shí)使用場景,Handler.post執(zhí)行。很多人覺得Handler相關(guān)的面試題都是八股文,這次我們就通過這個(gè)真是場景來給大家說說這個(gè)有意思的問題。
首先從onFragmentDestroyed方法會(huì)執(zhí)行在Fragment本身的onDestroyView之前,原來我們會(huì)在這個(gè)方法下執(zhí)行引用清空的操作。然后當(dāng)onDestroyView執(zhí)行的時(shí)候就會(huì)出現(xiàn)空指針異常了。那么Lifecycle有沒有提供一個(gè)在onDestroyView之后的方法呢?我們是不是可以考慮自己造一個(gè)呢?面試中,我們知道所有生命周期方法都是有主線程Handler來負(fù)責(zé)調(diào)度的,這也就是說活我么可以把生命周期方法認(rèn)為就是一個(gè)Message,當(dāng)onFragmentDestroyed執(zhí)行的時(shí)候,onDestroyView也已經(jīng)被添加到主線程的MessageQueue中,這個(gè)時(shí)候我們?cè)趐ost一個(gè)runnable,那么他的排序規(guī)則上來說,就必然在onDestroyView之后了。
這個(gè)庫另外一個(gè)優(yōu)點(diǎn)就是他同時(shí)支持反射和非反射的寫法。同時(shí)也支持了Activity,F(xiàn)ragment,View,F(xiàn)ragmentDialog,ViewHolder等等。反射寫法是基于非反射寫法的,所以也保證了底層庫的一致性。
//非反射寫法 private val viewBinding by viewBinding(ViewProfileBinding::bind) //反射寫法 private val viewBinding: ItemProfileBinding by viewBinding()
同時(shí)他的反射相關(guān)的混淆配置文件也非常有意思。
allowoptimization 指定對(duì)象可能會(huì)被優(yōu)化,即使他們被keep選項(xiàng)保留。所指定對(duì)象可能會(huì)被改變(優(yōu)化步驟),但可能不會(huì)被混淆或者刪除。該修飾符只對(duì)實(shí)現(xiàn)異常要求有用。
-keep,allowoptimization class * implements androidx.viewbinding.ViewBinding { public static *** bind(android.view.View); public static *** inflate(...); }
它只會(huì)keep實(shí)現(xiàn)了ViewBinding的類的bind和inflate方法。因?yàn)閂iewBinding會(huì)將所有的xml轉(zhuǎn)化成一個(gè)類實(shí)例,如果不刪除掉沒有實(shí)際被調(diào)用的類的情況下就會(huì)導(dǎo)致dex包變大,大家對(duì)于包體積優(yōu)化都是有追求的嗎。然后用了-keep,allowoptimization,這樣在混淆的代碼優(yōu)化過程中就可以刪除掉沒有被調(diào)用的ViewBinding類了。
“Android開發(fā)Viewbinding委托怎么實(shí)現(xiàn)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。