性能比较:映射LiveData值和Flow值



目前,我正在尝试在android中使用livedata和flow。我遇到的问题是,当涉及到映射livedata值和流值时,是否存在很大的性能差异,因为livedata映射是在主ui线程中执行的:

/**
* Returns a [LiveData] mapped from `this` LiveData by applying [transform] to each value set on
* `this` LiveData.
*
* This method is analogous to [io.reactivex.Observable.map].
*
* [transform] will be executed on the main thread.
*
* [...]
**/
public inline fun <X, Y> LiveData<X>.map(crossinline transform: (X) -> Y): LiveData<Y> =
Transformations.map(this) { transform(it) }

现在是技巧部分:假设我们有一个想要映射的livedata值。由于映射是在ui线程中执行的,因此我们将livedata值转换为流值:

public 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)
}
}
}

在将livedata观察者转换为流之后,我们在另一个线程(Dispatchers.IO)中成功地映射了这些值。但是现在我们不需要ui流了,所以我们把它转换回livedata值:

@JvmOverloads
public fun <T> Flow<T>.asLiveData(
context: CoroutineContext = EmptyCoroutineContext,
timeoutInMs: Long = DEFAULT_TIMEOUT
): LiveData<T> = liveData(context, timeoutInMs) {
collect {
emit(it)
}
}

现在的问题是:

  1. 与映射流值相比,映射livedata值是否对性能有较大影响
  2. 将livedata值转换为流值,然后将其转换回livedata是否会引入任何开销和/或性能问题?如果是,直接映射livedata值是否更好?

映射的例子是:

fun LiveData<WorkInfo>.collectStatus(): LiveData<Status<Unit>> = map { workInfo ->
when(workInfo.state) {
WorkInfo.State.ENQUEUED -> Status.loading()
WorkInfo.State.RUNNING -> Status.loading()
WorkInfo.State.SUCCEEDED -> Status.success(Unit)
WorkInfo.State.BLOCKED -> Status.failed("Workmanager blocked")
WorkInfo.State.FAILED -> Status.failed("Workmanager failed")
WorkInfo.State.CANCELLED -> Status.failed("Workmanager cancelled")
}
}

如果你想在不同的线程上执行映射,那么你应该使用LiveData.switchMapliveData(context) { }

livedata.switchMap { 
liveData(Dispatchers.IO) { 
emit(someValue)
}
}

或者去掉LiveData,到处使用Flow/StateFlow/SharedFlow/Channel

最新更新