Android基础-ViewModel初体验

174 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

ViewModel介绍

ViewModelAndroid官方开发JetPack推荐专门用于和页面交互的数据管理类。它可与页面Activity/Fragment生命周期绑定确保数据与页面生命周期同步以此达到最佳使用效果。例如页面A需要销毁重建,重新创建页面B。他们属于同一类型但是两个不同实例对象。但内部维护的数据源属于同一个在页面A销毁其数据过渡到页面B就需要使用到ViewModel了。

ViewModel使用

继承ViewModel创建页面自己TestViewModel对象。

class TestViewModel  : ViewModel(){
    var textIntValue : MutableLiveData<Int> = MutableLiveData<Int>()
}

Activity创建一个ViewModel对象。通过ViewModelProvider可创建TestViewModel类型对象可以为其value赋值。同时ViewModel可设置observe监听来知悉ViewModelvalue值是否发生了变化以此刷新UI展示结果。observethis是页面的生命周期保证监听回调返回是在安全生命周期内的避免空指针情况发生。

PS:ViewModel也可以不和页面生命周期绑定,同样的observe方法不入参LifecycleOwner即可。但切记需要自行管理监听回调在安全情况下使用回调结果。

var viewModel = ViewModelProvider(this).get(TestViewModel::class.java)
viewModel.textIntValue.value = 1
viewModel.textIntValue.observe(
    this
) { t ->
    run {
        findViewById<TextView>(R.id.tv_value).text = "viewModel $t"
    }
}

此外在Fragment中同样可以获取到和Activity一样的ViewModel对象。只要ViewModelProvider入参是Activity上下文即可,若Fragment入参上下文是this那么创建的ViewModel只是该Fragment自身的,这和ViewModelProvider内部实现逻辑有关所有的ViewModelHashMap形式保证内部全局类中。

viewModel = ViewModelProvider(requireActivity()).get(TestViewModel::class.java)
viewModel?.textIntValue?.observe(
    viewLifecycleOwner
) { t ->
    run {
        view.findViewById<TextView>(R.id.tv_value).text = "viewModel $t"
    }
}

实现ViewModel以及数据监听之后,当ViewModel数据发生变化后,Activity/Fragment两者皆可在同一个对象中监听到数值变化回调。这也大大减少了数据传递的开发量可以说是EventBus的便携式升级版,比起提供方法传参也更加解耦。

var value = viewModel?.textIntValue?.value ?: 0
if (viewModel?.textIntValue?.value != null) {
    value.plus(1).also {
        viewModel!!.textIntValue!!.value = it
    }
}

MutableLiveData和LiveData

MutableLiveDataLiveData最大区别是可变和不可变。MutableLiveData继承了LiveData抽象类,MutableLiveData提供了postValuesetValue方法。MutableLiveData就是为其新增了可对数据源操作的能力。同时postValuesetValue也存在不同作用。

  • setValue只能在主线程中使用不可在子线程操作
  • postValue可以在任何线程操作,因为它自身线程任务。
  • 但监听回调都是在主线程中发生。

小结

ViewModel在业务开发中是比较实用的,对于多个数据源能做到数据区分,同时又能对数据做隔离处理。页面可以只关心UI而不关心数据处理,UI页面开发会变得更加清爽,所有业务数据处理在ViewModel中进行。在很大程度上也解决了数据在多个页面同步的问题,不在想以前为了两个页面数据同步而设置方法或是接口互相调用"low代码"了。