安卓架构组件实战——ViewModel+LiveData

在谷歌官方提供的安卓架构组件中,有ViewModel、LiveData、Lifecycle、DataBinding等,他们共同组成了一个完整的MVVM架构,实现了视图与业务逻辑分离,并且提供友好的生命周期管理。本文不会涉及到这些组件的原理解析,百度能找到一堆的我就不重复造轮子了,直接上干货教你如何使用。

在使用这些组件之前,我们先来了解下MVVM:

一、MVVM

MVVM即 Model(数据) View(视图) ViewModel(数据视图管理器)

具体体现:

Model:bean(实体类)、网络请求相关、数据库相关
View:布局、View、Activity、Fragment 等UI相关
ViewModel:类似于MVP中的Presenter,用于从Model获取信息,传递给View进行显示,ViewModel与View是绑定在一起的,通过一定手段进行数据交互(例如LiveData)

二、LiveData+ViewModel

LiveData是可观察的数据持有者类。它具有生命周期感知功能,这意味着它能响应其他应用程序组件(例如Activity、Fragment或Service)的生命周期。这确保LiveData仅更新处于活动的生命周期状态的应用程序组件观察者。

在使用LiveData之前,你可以先去了解官方文档Lifecycle,或者查看我的博客:《安卓架构组件实战——Lifecycle》

ViewModel:用于Model层和View层数据交互的中间组件,架构组件为ViewModelUI控制器提供了帮助程序类,该类负责为UI准备数据。 ViewModel配置更改期间会自动保留对象,以便它们保存的数据可立即用于下一个Activity或Fragment实例。

View和ViewModel通过LiveData来传递消息和数据。LiveData是一个可观察的数据持有者,他可以让应用程序组件去观察LiveData中的数据是否发生改变。LiveData还会遵循应用程序组件(Activity,Fragment, Service)的生命周期状态来避免内存泄露,从而使你的APP不会消费太多的内存(LiveData具备生命周期感知。这意味着除非Activity/fragment是激活状态(onStart但是还没有onStop),要不然是不会发起回调的。当fragment调用onStop后, LiveData还会自动删除观察者)

LiveData通常和ViewModel一起使用,使用方法如下:

1.引入

//lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
//ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc02"

非androidx版本:(注意编译版本28以上,引入的support库也必须是28.0.0以上的)

// Lifecycle
implementation "android.arch.lifecycle:extensions:1.1.0"
//ViewModel
implementation "android.arch.lifecycle:viewmodel:1.1.0"
//LiveData
implementation "android.arch.lifecycle:livedata:1.1.0"

LiveData 是一个抽象类,它的实现子类有 MutableLiveData ,MediatorLiveData,常用的是 MutableLiveData。

使用如下:

继承ViewModel即可(kotlin写法,使用java的童鞋请自行翻译)

/**
 * 基础的ViewModel,可以封装一些通用操作
 *
 */
abstract class BaseViewModel : ViewModel(){
}

LiveData:

class HomeViewModel : BaseViewModel() {
    //定义一个MutableLiveData,设置Value即可
    val data = MutableLiveData<String>()

    fun setData(name: String) {
           //这里可以去获取网络数据,操作数据库等
          //主线程可以使用setValue() ,异步线程使用postValue()
          data.value = name
    }
}

在Fragment监听数据变化:

class HomeFragment : BaseFragment() {

    ...省略部分代码    

    private var homeViewModel: HomeViewModel? = null

    companion object {
        fun newInstance(): HomeFragment {
            return HomeFragment()
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        //获取ViewModel实例(如果我的ViewModele需要带参数怎么办?看文章后面)
        homeViewModel = ViewModelProviders.of(this)[HomeViewModel::class.java]

        //改变数据
        homeViewModel?.setData("测试")

        //监听ViewModel里面的data的数据变化
//        homeViewModel?.data?.observe(this,Observer<String>{data->{
//        } })
        homeViewModel?.data?.observe(this, Observer {
            mProgressDialog?.hide()
            Log.i("test", it)
        })

    }
}

这样就完成了LiveData和ViewModel的集成,不用我们去关注生命周期的事,简单明了,完整的代码请看:项目源码

后记

我们刚刚发现了,在Fragment获取ViewModel实例是通过如下方式获取的:

 homeViewModel = ViewModelProviders.of(this)[HomeViewModel::class.java]

这里它会去执行HomeViewModel的无参构造函数,那么我的ViewModel构造函数带参数怎么办?

ViewModelProviders.of方法里面提供了一种方法,传入一个ViewModelProviders.Factory对象即可,具体写法:

//构造函数带参数tips
class MyViewModel(private val tips:String?) :BaseViewModel() {

    val timeData = MutableLiveData<String>()

    init {
        val timer = Timer()

        timer.schedule(object : TimerTask() {
            override fun run() {
                val dataStr = TimeUtil.dateToSecondStr(Date())
                //异步线程使用postValue(),主线程用setValue()/postValue()
                timeData.postValue(tips+dataStr)
            }
        },0,1000)
    }
    
    //构造函数带参数,需要构建一个Factory,这样就可以用
    //ViewModelProviders.of(this, MyViewModel.Factory(tips)).get(MyViewModel::class.java)执行带参数的构造函数
    class Factory(private val tips:String?) : ViewModelProvider.Factory{
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return MyViewModel(tips) as T
        }
    }
}

调用:

myViewModel = ViewModelProviders.of(this, MyViewModel.Factory("当前时间:")).get(MyViewModel::class.java)
        

猜你喜欢

转载自blog.csdn.net/gs12software/article/details/103307967