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 作为示例中的类型。另外,我认为它很容易出错,并且链接范围函数的可读性很差,所以我会在没有它们的情况下进行。
- 将其设为挂起函数,而不是启动协程。在 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")
}
}
- 公开 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")
}
}
}
您可以使用 StateFlow 而不是 LiveData 执行与 2 相同的操作。
您可以公开带有回调参数的常规函数,而不是挂起函数。但在已经使用协程的项目中,这是一个过于复杂的解决方案。
好吧,对于阅读这篇文章的其他人,我做了@Tenfour04 建议的更改,并且还添加了 Dispatchers.IO
作为 viewModelScope.launch
方法的参数,并且还必须更改 _steps.value =
... _step.postValue(...)
感谢所有回答的人
这是我遇到的问题
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 作为示例中的类型。另外,我认为它很容易出错,并且链接范围函数的可读性很差,所以我会在没有它们的情况下进行。
- 将其设为挂起函数,而不是启动协程。在 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")
}
}
- 公开 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")
}
}
}
您可以使用 StateFlow 而不是 LiveData 执行与 2 相同的操作。
您可以公开带有回调参数的常规函数,而不是挂起函数。但在已经使用协程的项目中,这是一个过于复杂的解决方案。
好吧,对于阅读这篇文章的其他人,我做了@Tenfour04 建议的更改,并且还添加了 Dispatchers.IO
作为 viewModelScope.launch
方法的参数,并且还必须更改 _steps.value =
... _step.postValue(...)
感谢所有回答的人