概述
文章目录
- 1. Flow与LiveData相互转换
- 1.1. Flow转换成LiveData
- 1.2. LiveData转换成Flow
1. Flow与LiveData相互转换
1.1. Flow转换成LiveData
Flow提供了asLiveData()扩展函数来将Flow转换成LiveData:
//CoroutineLiveData.kt
@JvmOverloads
fun <T> Flow<T>.asLiveData(
context: CoroutineContext = EmptyCoroutineContext,
timeoutInMs: Long = DEFAULT_TIMEOUT
): LiveData<T> = liveData(context, timeoutInMs) {
collect {
emit(it)
}
}
fun <T> liveData(
context: CoroutineContext = EmptyCoroutineContext,
timeoutInMs: Long = DEFAULT_TIMEOUT,
@BuilderInference block: suspend LiveDataScope<T>.() -> Unit
): LiveData<T> = CoroutineLiveData(context, timeoutInMs, block)
asLiveData()方法主要就是创建一个CoroutineLiveData对象,CoroutineLiveData继承于MediatorLiveData,先看一下这个类的初始化方法:
//class CoroutineLiveData
init {
// use an intermediate supervisor job so that if we cancel individual block runs due to losing
// observers, it won't cancel the given context as we only cancel w/ the intention of possibly
// relaunching using the same parent context.
val supervisorJob = SupervisorJob(context[Job])
// The scope for this LiveData where we launch every block Job.
// We default to Main dispatcher but developer can override it.
// The supervisor job is added last to isolate block runs.
val scope = CoroutineScope(Dispatchers.Main.immediate + context + supervisorJob)
blockRunner = BlockRunner(
liveData = this,
block = block,
timeoutInMs = timeoutInMs,
scope = scope
) {
blockRunner = null
}
}
这里构造了一个SupervisorJob对象,根据注释可知这是用于隔离父子协程的,以达到取消子协程而不取消父协程的作用。还构造了一个BlockRunner对象,用于包装LiveData及Flow的collect操作,这里的block即代表Flow的collect操作。根据LiveData原理,在生命周期拥有者的生命周期发上变化时会通知LiveData的生命周期观察者,当生命周期拥有者的生命周期状态变为active状态时,LiveData的onActive()方法会被调用:
//class CoroutineLiveData
override fun onActive() {
super.onActive()
blockRunner?.maybeRun()
}
//class BlockRunner
fun maybeRun() {
cancellationJob?.cancel()
cancellationJob = null
if (runningJob != null) {
return
}
runningJob = scope.launch {
val liveDataScope = LiveDataScopeImpl(liveData, coroutineContext)
block(liveDataScope)
onDone()
}
}
这里先忽略cancellationJob,先创建一个LiveDataScopeImpl对象,然后以其为参数执行block代码块,执行完后再执行onDone代码块,即blockRunner = null。回到block代码块赋值的地方,会执行Flow的扩展方法collect(),这一过程就可以参考Kotlin中flow发射与接收分析。简要看一下这一步的代码:
public suspend inline fun <T> Flow<T>.collect(crossinline action: suspend (value: T) -> Unit): Unit =
collect(object : FlowCollector<T> {
override suspend fun emit(value: T) = action(value)
})
当原Flow中有数据发射时,action lambda表达式即会执行,这里即会执行LiveDataScopeImpl对象中的emit()方法:
//class LiveDataScopeImpl
override suspend fun emit(value: T) = withContext(coroutineContext) {
target.clearSource()
target.value = value
}
这里的target即使本LiveData对象,执行其setValue()方法就会触发LiveData中的观察者被通知。从上面的分析可知,在生命周期拥有者处于active状态时,会触发对原Flow的collect操作,下面看一下当生命周期拥有者处于inactive状态时,又做了什么:
//class CoroutineLiveData
override fun onInactive() {
super.onInactive()
blockRunner?.cancel()
}
//class BlockRunner
@MainThread
fun cancel() {
if (cancellationJob != null) {
error("Cancel call cannot happen without a maybeRun")
}
cancellationJob = scope.launch(Dispatchers.Main.immediate) {
delay(timeoutInMs)
if (!liveData.hasActiveObservers()) {
// one last check on active observers to avoid any race condition between starting
// a running coroutine and cancelation
runningJob?.cancel()
runningJob = null
}
}
}
可以看到开启一个协程,延迟timeoutInMs毫秒,默认是5秒,然后将runningJob协程取消掉。这里延迟5秒主要是为了避免在横竖屏切换时做无谓的工作,当横竖屏切换时会先执行onInactive()方法再执行onActive()方法,档其间隔小于5秒时runningJob?.cancel()还没有执行cancellationJob协程就被取消掉了,因此根本没有取消对原Flow的collect操作。
1.2. LiveData转换成Flow
LiveData提供了扩展函数asFlow()来将LiveData转换成Flow:
fun <T> LiveData<T>.asFlow(): Flow<T> = flow {
val channel = Channel<T>(Channel.CONFLATED)
val observer = Observer<T> {
channel.offer(it)
}
withContext(Dispatchers.Main.immediate) {
observeForever(observer)
}
try {
for (value in channel) {
emit(value)
}
} finally {
GlobalScope.launch(Dispatchers.Main.immediate) {
removeObserver(observer)
}
}
}
这段代码就相对简单了,构造了一个Channel对象来做为中转,然后再给LiveData对象添加一个Observer观察者,当观察者被通知时即将该通知数据放入Channel中,然后在将该Channel对象中的数据取出构造成flow。
最后
以上就是平淡棒棒糖为你收集整理的Coroutine之Flow与LiveData相互转换1. Flow与LiveData相互转换的全部内容,希望文章能够帮你解决Coroutine之Flow与LiveData相互转换1. Flow与LiveData相互转换所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复