Kotlin 房间查询未及时返回

Kotlin room query not returning in time

这是我遇到的问题

viewModelScope.launch {
            workout?.let { workout ->
                // Workout is not null
                steps = stepDao.getWorkoutSteps(workout.workoutId)
                Log.e(tag, "steps old : ${workout.workoutId}")
            } ?: run {
                // Workout is null, let's create it
                newWorkoutAndStepsId = workoutDao.insert(Workout("")).toInt()
                Log.e(tag, "steps new : $newWorkoutAndStepsId")

                var step1id = stepDao.insert(Step("Warm Up Jumping Jacks", 1, false, "minute", newWorkoutAndStepsId)).toInt()
                Log.e(tag, "steps new : new step id $step1id")
                stepDao.insert(Step("Rest", 15, true, "second", newWorkoutAndStepsId))

                steps = stepDao.getWorkoutSteps(newWorkoutAndStepsId)


                //steps = stepDao.getWorkoutSteps(25)
            }
        }

在新锻炼的情况下,这些步骤不会得到 returned,如果我硬编码 id 然后他们就会这样做,日志都如预期的那样 return id,但仍然是步骤未 returned

谢谢!

协程是异步的。您不能期望协程在启动后立即可用。 See here for an explanation.

根据评论,您说您希望在 Fragment 中使用这些步骤。有几种方法可以做到这一点。

我不知道步数的类型,所以我将只使用 WorkoutSteps 作为示例中的类型。另外,我认为它很容易出错,并且链接范围函数的可读性很差,所以我会在没有它们的情况下进行。

  1. 将其设为挂起函数,而不是启动协程。在 Fragment 中,从协程中调用挂起函数以获取值并在协程中使用它。
suspend fun getSteps(): WorkoutSteps = when (val workout = workout) {
  null -> { // Workout is null, let's create it
    newWorkoutAndStepsId = workoutDao.insert(Workout("")).toInt()
    Log.e(tag, "steps new : $newWorkoutAndStepsId")

    val step1id = stepDao.insert(Step("Warm Up Jumping Jacks", 1, false, "minute", newWorkoutAndStepsId)).toInt()
    Log.e(tag, "steps new : new step id $step1id")
    stepDao.insert(Step("Rest", 15, true, "second", newWorkoutAndStepsId))
    stepDao.getWorkoutSteps(newWorkoutAndStepsId)
  }
  else -> stepDao.getWorkoutSteps(workout.workoutId).also {
     Log.e(tag, "steps old : $it")
  }
}
  1. 公开 Fragment 的 LiveData 以持续观察结果。 LiveData 最初没有任何价值。调用 refreshSteps() 后,结果将稍后通过 LiveData 传入。所以 Fragment 应该观察 LiveData 并单独调用 refreshSteps()
private val _steps = MutableLiveData<WorkoutSteps>()
val steps: LiveData<WorkoutSteps> get() = _steps

fun refreshSteps() = viewModelScope.launch {
  _steps.value = when(val workout = workout) {
    null -> { // Workout is null, let's create it
      newWorkoutAndStepsId = workoutDao.insert(Workout("")).toInt()
      Log.e(tag, "steps new : $newWorkoutAndStepsId")

      val step1id = stepDao.insert(Step("Warm Up Jumping Jacks", 1, false, "minute", newWorkoutAndStepsId)).toInt()
      Log.e(tag, "steps new : new step id $step1id")
      stepDao.insert(Step("Rest", 15, true, "second", newWorkoutAndStepsId))
      stepDao.getWorkoutSteps(newWorkoutAndStepsId)
    }
    else -> stepDao.getWorkoutSteps(workout.workoutId).also {
      Log.e(tag, "steps old : $it")
    }
  }
}
  1. 您可以使用 StateFlow 而不是 LiveData 执行与 2 相同的操作。

  2. 您可以公开带有回调参数的常规函数​​,而不是挂起函数。但在已经使用协程的项目中,这是一个过于复杂的解决方案。

好吧,对于阅读这篇文章的其他人,我做了@Tenfour04 建议的更改,并且还添加了 Dispatchers.IO 作为 viewModelScope.launch 方法的参数,并且还必须更改 _steps.value = ... _step.postValue(...) 感谢所有回答的人