Search code examples
kotlinandroid-livedatamutablelivedatamediatorlivedata

Kotlin \ Android - LiveData async transformation prevent previous result


So I have a LiveData that I transform to an async function that takes a while to execute (like 2 seconds sometimes, or 4 seconds).

sometimes the call takes long, and sometimes it's really fast (depends on the results) sometimes it's instant (empty result)

the problem is that if I have 2 consecutive emits in my LiveData, sometimes the first result takes a while to execute, and the second one will take an instant, than it will show the second before the first, and than overwrite the result with the earlier calculation,

what I want is mroe of a sequential effect. (kinda like RxJava concatMap)

 private val _state = query.mapAsync(viewModelScope) { searchString ->
        if (searchString.isEmpty()) {
            NoSearch
        } else {
            val results = repo.search(searchString)
            if (results.isNotEmpty()) {
                Results(results.map { mapToMainResult(it, searchString) })
            } else {
                NoResults
            }
        }
    }




@MainThread
fun <X, Y> LiveData<X>.mapAsync(
    scope: CoroutineScope,
    mapFunction: androidx.arch.core.util.Function<X, Y>
): LiveData<Y> {
    val result = MediatorLiveData<Y>()
    result.addSource(this) { x ->
        scope.launch(Dispatchers.IO) { result.postValue(mapFunction.apply(x)) }
    }
    return result
}

how do I prevent the second result from overwriting the first result?


Solution

  • @MainThread
    fun <X, Y> LiveData<X>.mapAsync(
        scope: CoroutineScope,
        mapFunction: (X) -> Y,
    ): LiveData<Y> = switchMap { value ->
        liveData(scope.coroutineContext) {
            withContext(Dispatchers.IO) {
                emit(mapFunction(value))
            }
        }
    }