Navigation學(xué)習(xí)筆記之二--fragment保存狀態(tài)

fragment狀態(tài)保存問題

在使用jetpack的navigation組件過程中遇到的一個(gè)問題就是它內(nèi)部使用replace方式切換的fragment,這樣會(huì)導(dǎo)致fragment生命周期重走。這樣就不會(huì)保留之前的頁面狀態(tài)了,這就有點(diǎn)不友好了。查了一下大家使用的解決方案,主要有兩種

  • 使用hide/show方式取代replace方式

  • 繼續(xù)使用replace方式,想辦法保存頁面狀態(tài)

經(jīng)過對(duì)比這兩種方案發(fā)現(xiàn),navigation原生方式更合理。因?yàn)閔ide/show方案對(duì)內(nèi)存不友好的弊端很難消除,且項(xiàng)目越大,問題越明顯。

使用原生方式,就面臨了另一個(gè)問題,如何保存頁面狀態(tài)?Navigation設(shè)計(jì)初衷就是UI與數(shù)據(jù)分離,所以這個(gè)問題,拆解成兩個(gè)問題分別解決:

1.頁面問題

Google官方有推薦方案,就是保存view。

abstract class BaseFragment : Fragment() {  
    private var rootView : View ?= null  

    override fun onCreateView(  
        inflater: LayoutInflater,  
        container: ViewGroup?,  
        savedInstanceState: Bundle?  
    ): View? {  
        if (rootView == null){  
             rootView = inflater.inflate(getLayoutId(), null)  
        }  
        return rootView  
    }  
    abstract fun getLayoutId():Int  
}

2.數(shù)據(jù)問題

通過viewmodel保存數(shù)據(jù),這里引出兩個(gè)問題

  • 1.viewmodel的生命周期跟隨誰

跟隨fragment,那么fragment銷毀的時(shí)候,viewmodel就沒有了。跟隨activity,那么activcity不銷毀的情況下,viewmodel就一直存在

看源碼發(fā)現(xiàn),Navigation切換fragment用的是childFragmentManager,所有的fragment的父fragment都是NavHostFragment,于是跟隨requireParentFragment()就可以了

override fun initVM(): StickerViewModel = ViewModelProvider(requireParentFragment())[StickerViewModel::class.java]
  • 2.fragment重新創(chuàng)建的時(shí),重新注冊(cè)u(píng)iStatus的observer,注冊(cè)的時(shí)候,livedata會(huì)把上次數(shù)據(jù)重新發(fā)送一遍。

解決方法也很簡(jiǎn)單,只需要在基類的fragment中清除一下狀態(tài)就好了

還有一個(gè)問題,如果跳轉(zhuǎn)fragment的時(shí)候,攜帶了參數(shù),重新回到這個(gè)fragment的時(shí)候也會(huì)重新獲取到。這個(gè)也是需要清除的

綜合以上各種問題的解決方案,BaseFragment應(yīng)當(dāng)如下

abstract class BaseVMFragment<VM : BaseViewModel> : Fragment() {  

    protected var mContentView: View? = null  
    protected lateinit var mViewModel: VM  
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {  
        if (mContentView == null) {  
            mContentView = inflater.inflate(getLayoutResId(), container, false)  
        }  
        return mContentView  
    }  

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {  
        mViewModel = initVM()  
        if (isNeedClearState()) {  
            mViewModel.clearUIState()  
        }  
        initView()  
        initData()  
        startObserve()  
        super.onViewCreated(view, savedInstanceState)  
    }  

    override fun onDestroyView() {  
        //需要清除參數(shù)和uiState  
        arguments?.clear()  
        super.onDestroyView()  
    }  

    open fun isNeedClearState(): Boolean {  
        return true  
    }  

    abstract fun getLayoutResId(): Int  
    abstract fun initVM(): VM  
    abstract fun initView()  

    abstract fun initData()  

    abstract fun startObserve()  

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容