本篇文章主要介绍CoroutineLiveData的使用,这是一个基于协程+MediatorLiveData实现的一种build构建livedata的类。
LiveData
的方式class MainViewModel: ViewModel() {
//可变不对外暴漏
private val _data = MutableLiveData<String>()
//对外暴漏
val data: LiveData<String>
get() = _data
fun login() {
//经过一些列网络请求
_data.value = "shengxu"
}
}
然后再Activity中添加观察者等等,请注意这里有个小细节:
对外暴漏不可变的Livedata使用的是get() = _data而不是val data: LiveData<String> = _data,这样做的好处是前者减少了一个属性的声明。
如果我们想要实现先从本地数据库读取数据,再从远程网络获取数据源,只能这样实现:
fun getData() {
//从数据库读取数据
_data.value = "bendi"
//经过一些列网络请求
_data.value = "shengxu"
}
这样有一个不好的问题,可能由于程序的不当逻辑,发生多次getData()
的操作,比如横竖屏切换,ViewModel
不会销毁且保存着原来的数据,而程序错把getData()
的请求放在了比如Activity的onStart()
方法中,即使ViewModel有数据也会发生重复向服务器获取数据的情况。
针对于这种情况,我们可以将getData()
方法放到MainViewModel
的init{}
代码块中实现,而CoroutineLiveData
提供了一种更好的方式。
CoroutineLiveData
build模式构建val mLiveData = liveData {
//发送单个内容
emit("10")
//发送livedata
emitSource(_data)
}
实际上这个就是创建了一个CoroutineLiveData
类型的LiveData
,下面的emit()
和emitSource()
方法就是基于CoroutineLiveData
实现。
直接通过livedata{}
扩展方法动态构建一个不可变的LiveData
,调用emit()
或者emitSource()
方法就相当于调用之前LiveData
的setValue()
方法,当然后者实现上稍微复杂些。
emit()
这里随便拿官方的例子演示:
val user = liveData<Model> {
var backOffTime = 1_000
var succeeded = false
while(!succeeded) {
try {
emit(api.fetch(id))
succeeded = true
} catch(ioError : IOException) {
delay(backOffTime)
//每次轮询执行的时间间隔都会增加,最大60s
backOffTime *= minOf(backOffTime * 2, 60_000)
}
}
}
请注意livedata{}
代码块中的内容默认是执行在主线程中的。
在这里我们调用api.fetch(id)
模拟轮询执行网络请求直到成功,每次执行的时间间隔都比上次大一些,相比较于在MainViewModel
的init{}
执行该逻辑,放到livedata的构造代码块中执行显得更加方便,既不会导致init{}
代码块过于臃肿,也更加符合单一原则或者封装性(自己感觉...)。
emitSource()
这个方法需要传入一个LiveData
类型的参数:
override suspend fun emitSource(source: LiveData<T>): DisposableHandle =
withContext(coroutineContext) {
return@withContext target.emitSource(source)
}
大家应该都用过MediatorLiveData
,emitSource()
底层的实现就是该类,所以该方法可以理解为监听传入的LiveData<T>
数据源变化并将数据赋值到我们通过livedata{}
扩展创建的LiveData
中。
请注意如果在调用emit()方法之前调用了emitSource(),会移除emitSource()添加的LiveData数据源监听,使之无效,具体的源码分析将放到下一篇文章中。
本篇文章主要介绍了普通LiveData的构建方式和通过livedata{}
构建:
阅读量:1988
点赞量:0
收藏量:0