本文首发于微信公众号「Android开发之旅」,欢迎关注 ,获取更多技术干货
前一篇文章咱们讲解了Lifecycle的具体使用,为了更好的理解,本篇咱们将LiveData和ViewModel放在一块儿讲解,经过简单的Demo来讲明两者之间的协同工做。java
那么咱们为何要使用LiveData和ViewModel呢?他们有什么优点呢? android
在LiveData出现以前,通常状态分发咱们使用EventBus或者RxJava,这些都很容易出现内存泄漏问题,并且须要咱们手动管理生命周期。而LiveData则规避了这些问题,LiveData是一个持有Activity、Fragment生命周期的数据容器。当数据源发生变化的时候,通知它的观察者更新UI界面。同时它只会通知处于Active状态的观察者更新界面,若是某个观察者的状态处于Paused或Destroyed时那么它将不会收到通知。因此不用担忧内存泄漏问题。数据库
ViewModel将视图和逻辑进行了分离。Activity或者Fragment只负责UI显示部分。具体的网络请求或者数据库操做则有ViewModel负责。这样避免了视图的臃肿和代码的耦合。经过下面这张ViewModel生命周期能够看出,当屏幕发生旋转而致使Activity被销毁并从新建立时,ViewModel并无被销毁,从而帮助咱们在Activity从新建立后获取数据更新UI。它和onSaveInstanceState方法相比更有优点,由于onSaveInstanceState方法只不适合大量数据的恢复操做,只能恢复少许而且被序列化和反序列化的数据,而ViewModel不只支持大量数据,还不须要序列化、反序列化操做。segmentfault
首先咱们在build.gradle中添加依赖:微信
def lifecycle_version = "2.1.0" // ViewModel and LiveData implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"/
而后咱们建立ViewModel类,建立类继承ViewModel,并在其中建立LiveData:网络
class SecondViewModel : ViewModel() { var userData: MutableLiveData<UserInfo> = MutableLiveData() /** * 模拟获取数据 */ fun getUserInfo() { val user = UserInfo("李四",(1000..5000).random()) userData.postValue(user) } }
由于LiveData是抽象类,MutableLiveData是它的一个实现类。其中定义了postValue和setValue用来通知观察者更新数据。postValue为异步操做。setValue为同步操做。架构
接着咱们在Activity中建立ViewModel并将UI组件和LiveData进行绑定以便进行数据的更新。app
class SecondActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activiry_second) val secondViewModel = ViewModelProviders.of(this).get(SecondViewModel::class.java) secondViewModel.userData.observe(this, Observer { mTvShow.text = "姓名:${it.name} \n薪水:${it.salary}" }) /** * 模拟数据源更新 */ mBtnData.setOnClickListener { secondViewModel.getUserInfo() } } }
这里经过ViewModelProviders来获取ViewModelProvider在经过get方法来获取ViewModel实例。咱们经过button按钮注册了一个点击事件来模拟数据源数据的更新。dom
若是咱们想对从服务端获取到的数据进行修改可使用Transformations操做符。分为Map和switchMap两种。switchMap须要返回一个LiveData对象。异步
Transformations.map
Transformations.map(secondViewModel.userData, object : Function<UserInfo, UserInfo> { override fun apply(userInfo: UserInfo): UserInfo { userInfo.name = "张三" return userInfo } }).observe(this, Observer { mTvShow.text = "姓名:${it.name} \n薪水:${it.salary}" })
这就将name从新赋值为“张三”。
Transformations.switchMap
好比咱们有些数据须要依赖其余数据进行查询,就可使用switchMap。
Transformations.switchMap(secondViewModel.userData, object : Function<UserInfo, LiveData<UserInfo>> { override fun apply(userInfo: UserInfo): LiveData<UserInfo> { return secondViewModel.getUserName(userInfo) } }).observe(this, Observer { mTvShow.text = "姓名:${it.name} \n薪水:${it.salary}" })
在ViewModel中定义getUserName方法
fun getUserName(userInfo: UserInfo): LiveData<UserInfo> { userInfo.name = userInfo.name + "switchMap" switchMapData.value = userInfo return switchMapData }
当咱们页面须要多个不一样的数据源的时候,若是咱们都是单独的使用LiveData,会致使Activity中定义不少observe,出现不少多余的代码。MediatorLiveData就为解决这个问题的。它能够将多个LiveData合并在一块儿,只须要定义一次observe就能够。
var data1: MutableLiveData<UserInfo> = MutableLiveData() var data2: MutableLiveData<UserInfo> = MutableLiveData() var mediatorLiveData: MediatorLiveData<UserInfo> = MediatorLiveData() val user1 = UserInfo("李四1", (1000..5000).random()) val user2 = UserInfo("李四2", (1000..5000).random()) data1.postValue(user1) data2.postValue(user2) mediatorLiveData.addSource(data1, object : Observer<UserInfo> { override fun onChanged(info: UserInfo) { mediatorLiveData.value = info } }) mediatorLiveData.addSource(data2, object : Observer<UserInfo> { override fun onChanged(info: UserInfo) { mediatorLiveData.value = info } })
这个咱们定义了两个MutableLiveData表示正常的数据获取。MediatorLiveData经过addSource方法将data1和data2合并一块儿组成新的LiveData。onChanged回调表示的是当data1和data2数据源数据发送变化的时候进行回调。通知界面UI进行数据刷新。
咱们在Activity中使用:
secondViewModel.mediatorLiveData.observe(this, Observer { if (it.name.contains("1")) { mTvShow.text = "姓名:${it.name} \n薪水:${it.salary}" } else { mTvShowOther.text = "姓名:${it.name} \n薪水:${it.salary}" } })
这里就简单的经过name来判断不一样的数据源类型。这样就将data1和data2首次请求的数据在界面展现了。上文也讲了onChanged是监听data1和data2数据变化的。这里咱们在XML布局文件中新加一个button按钮用来模拟数据源变化。
而后在ViewModel中第一模拟刷新方法:
/** * 模拟data1和data2数据源改变 */ fun update() { val updateUser1 = UserInfo("李四1 update", (1000..5000).random()) val updateUser2 = UserInfo("李四2 update", (1000..5000).random()) data1.postValue(updateUser1) data2.postValue(updateUser2) }
postValue执行完成后onChanged方法将接受到回调并通知UI更新数据。
若是观察者的生命周期处于STARTED或RESUMED状态,则LiveData认为观察者处于活动状态。若是咱们知道何时是active和inactive,那么咱们能够本身实现LiveDta。因此LiveData提供了两个方法,分别为onActive()与onInactive()。并给出了官方Demo:
class StockLiveData(symbol: String) : LiveData<BigDecimal>() { private val stockManager = StockManager(symbol) private val listener = { price: BigDecimal -> value = price } override fun onActive() { stockManager.requestPriceUpdates(listener) } override fun onInactive() { stockManager.removeUpdates(listener) } }
onActive方法被调用说明如今有活动着的观察者,因此添加监听以进行数据的更新。onInactive方法被调用说明没有活动的观察者因此要移除监听。
咱们使用StockLiveData:
class MyFragment : Fragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { StockLiveData.get(symbol).observe(this, Observer<BigDecimal> { price: BigDecimal? -> // Update the UI. }) }
Android Jetpack架构组件 — Lifecycle入坑指南
Android Jetpack架构组件 — Room入坑详解