android - Are coroutines worth using with type mapping?
问题描述
Is it worth calling the coroutines in order to perform type mapping operations? Or it's going to be too much code bloating and/or overhead?
So the scenario is the following:
Repo returns objects of
LiveData<List<A>>
View needs objects of type
LiveData<<List<GUI_A>>
ViewModel
exposesLiveData<GUI_A>
by usingTransformations.map
and the sourceLiveData<A>
coming from the repo.
The Transformations.map
code looks something like this
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.map(repoData) {
it.map { GUI_A.fromRepoObject(it) }
}
The function fromRepoObject
only maps properties from the first object to the new instance of the second one.
The idea is to use coroutines in the map function to improve performance; but I don't know if it is going to be worth the hassle:
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.map(repoData) {
it.map { async { GUI_A.fromRepoObject(it) } }
.map { it.await() }
}
解决方案
The definitive answer, and I hate it, is that it depends.
Switching thread's context doesn't come for free and it has some accumulated overhead on doing so you have to watch out for data's magnitude before considering one thing or another.
- Mapping 15 elements? Probably not worth it.
- Mapping 1000? Maybe! do they have nested lists and maps that should also be mapped?
- Mapping 1_000_000? Definitely!
We should also watch out for our mapping implementations.
The given example:
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.map(repoData) {
it.map { async { GUI_A.fromRepoObject(it) } }
.map { it.await() }
}
It's a don't do.
You see; LiveData
assures that the code observing the LiveData
is running on the main thread. On one hand that's good because it assures main safety but on the other hand it's "bad" in this case because the main thread waits for all of the corutines to finish their mapping operations before pushing a value.
A smarter approach to this, assuming we're in a ViewModel
may be:
class SampleVM: ViewModel(){
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.switchMap(repoData) { listA ->
val result = MutableLiveData<List<GUI_A>>()
// Don't block the UI thread by running in a coroutine
viewModelScope.launch {
listA
// Parallelize computation
.map { async(Dispatchers.Default) { GUI_A.fromRepoObject(it) }
// The viewModelScope job will await for all coroutines to finish mapping
.map { it.await() }
// Post the result to into the live data
.let { result.postValue(it) }
}
result
}
}
推荐阅读
- vue.js - 如何删除尾部斜杠?
- reactjs - 使用 combineReducers 将 2 个减速器合二为一
- pandas - pandas count groupy 2 属性
- javascript - 如何在数组Javascript中推送对象?
- c# - Prism 7.2 WPF - ViewModelLocationProvider 的可能问题
- r - 基于R中数据框中组内的向量对列值重新排序
- python - Pandas Dataframe 高级拆分
- swift - 将类型推断为泛型函数的方法
- sql - Postgres DB 中的两个表,跨表维护唯一数据
- c# - 计数器未在统一 UI 上更新,但变量为