android - 使用 launch() 范围时无法为 LiveData 变量赋值,但可以使用 runBlocking() 为 LiveData 赋值

标签 android kotlin coroutine kotlin-coroutines

我有一个 LiveData 变量,我想在收到来自 HTTP 请求 的响应后为其赋值。我在 launch{} 范围内分配这个值。但是,当我测试代码以查看实际已分配值时,测试失败并指出该值为 null

我尝试了另一种选择,即使用 runBlocking {} 范围而不是 launch {} 范围,并且我的测试用例通过了。用于网络的库是 Retrofit

下面是使用 launch() 并使测试用例失败的代码。

private var _state = MutableLiveData<State>()
val state: LiveData<State>
  get() = _state 

private var job = Job()

private val uiScope = CoroutineScope(job + Dispatchers.Main)

init {
    executeRequest(....)
}

// Test cases fails with this function
private fun executeRequest(params) {
  uiScope.launch {
    val deferred = repository.getApi()
        .requestAsync(params)

    try {
        val response = deferred.await()

        _state.value = StateSuccess(response)
    } catch (e: Exception) {
        _state.value = StateError("Failure: $e.message")
    }
  }
}

下面是使用 runBlocking() 并使测试用例通过的代码。

private var _state = MutableLiveData<State>()
val state: LiveData<State>
  get() = _state 

private var job = Job()

private val uiScope = CoroutineScope(job + Dispatchers.Main)

init {
    executeRequest(....)
}

// Test cases passes with this function
private fun executeRequest(params) {
  runBlocking {
    val deferred = repository.getApi()
        .requestAsync(params)

    try {
        val response = deferred.await()

        _state.value = StateSuccess(response)
    } catch (e: Exception) {
        _state.value = StateError("Failure: $e.message")
    }
  }
}

这是测试用例

val viewModel = MyViewModel(fakeClientRepository)

val observer = Observer<State> {}

try {
    viewModel.state.observeForever(observer)

    assert(viewModel.state.value == StateSuccess("success"))
} finally {
    viewModel.state.removeObserver(observer)
}

为什么 launch() 没有将值分配给 LiveData 变量?

最佳答案

尝试使用 Dispatchers.IO 调度程序,然后将值分配给 LiveData,使用 postValue() 而不是 value

private fun executeRequest(params) {
  uiScope.launch {
    withContext(Dispatcher.IO){
 val deferred = repository.getApi()
        .requestAsync(params)
    try {
        val response = deferred.await()
        _state.postValue(RESPONSE)
    } catch (e: Exception) {
        _state.postValue(StateError("Failure: $e.message"))
    }

    }
  }
}

关于android - 使用 launch() 范围时无法为 LiveData 变量赋值,但可以使用 runBlocking() 为 LiveData 赋值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59081832/

相关文章:

python - 使android Python服务在挂起状态下运行

java - 以 Svg 形状写入缩放文本

android - Kotlin Android 中 "This AsyncTask class should be static or leaks might occur"的正确方法是什么?

kotlin flow onEach 没有被触发

android - 在平板电脑上模拟较小的屏幕?

android - 更改蓝牙低功耗 gatt 超时或刷新读取流以更快地检测断开事件

kotlin - 接口(interface)的继承 - 在 Kotlin 中扩展一个接口(interface)

go - 并行获取多个字段的模式

kotlin - 为什么 CompletableFuture 和 ListenableFuture 的协程构建器之间存在差异?

android - react 原生 : onPress in Android side somehow triggers onNavigationStateChange