一起来学Android Jetpack - Navigation(二)

327 阅读2分钟

上篇文章我们学习了Navigation的基本使用和一些进阶使用,这篇文章主要时用力啊讲解我们在使用Navigation时遇到的一些问题。

Fragment状态保存的问题

Navigation组件内部是使用replace方式切换的fragment,这样就会导致Fragment生命周期重走,所以之前的页面状态以及数据都不会保留,这对我们来说就不是很友好了。网上的解决思路无非两种:

  • 使用hide/show方式取代replace方式
  • 继续使用replace方式,想办法保存页面状态

两种方案对比,hide/show方案对内存不友好的弊端很难消除,且项目越大,问题越明显,再有就是需要大量研究Navigation并改造Navigation,成本较高,也与Google设计Navigation的初衷相悖。所以我们选择第二种思路。

举个栗子:A-B ,随后B返回A,其实只是重建了view,Fragment还是原来的Fragment。它内部持有的viewModel没变。所以我们可以拆解为两个问题解决:

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  
}

1.数据问题

ViewModel + DataBinding 自动适配Navigation的实例保存问题。也是谷歌推荐 MVVM 框架的原因,这也是 DataBinding 的魅力所在。

我们在点击一个按钮时随意存一个值,跳转到别的页面,再跳回来。

class OneFragmentViewModel : BaseViewModel() {
    var txt: String = ""
}
override fun initialize(savedInstanceState: Bundle?) {
    mBinding.tv.setOnClickListener {
        Log.i("damaris", "initialize: "+mViewModel.txt)
        mViewModel.txt="哈哈"
        val action =
            OneFragmentDirections.actionOneFragment2ToThreeFragment2()
        findNavController().navigate(action)
    }
}

打印情况:第一次空字符串,第二次值为哈哈。

当然如果不使用ViewModel + DataBinding也想解决数据问题也是可以的,我们上面说了,fragment还是原来的fragment,所以它持有的成员变量也是存在的,所以我们也可以使用成员变量来进行数据恢复,但是如果数据量变大,就十分不方便了,而且更改屏幕、或者内存不足的情况下,成员变量都会被回收掉。所以最好的方案还是Google自己推荐的方案。