Вы делаете это неправильно. Возможно, у вас есть неправильные представления о параллелизме или задачах, которые выполняются одновременно.
Позвольте мне развеять ваши сомнения.
- запуск не блокируется, он запускается и забывается. Никогда не знаешь, когда установлено значение. Единственное, что вы можете сделать, - это вызвать
join()
, чтобы убедиться, что это выполнено. - Но все же использование блока запуска не очень хорошо оптимизировано для задач, где вы хотите получить результат от сопрограммы. Здесь мы используем async / withContext.
async
вызывается в CoroutineScope, а withContext
- это функция верхнего уровня, которая ожидает CoroutineContext в качестве своего параметра. withContext
приостанавливает выполнение вызывающая сопрограмма, пока она не будет завершена. В то время как async
этого не делает, возвращаемое значение async
- Deferred<T>
, на котором, когда вы вызываете .await()
, вызывающая сопрограмма приостанавливается до тех пор, пока не будет завершена задача, аналогичная withContext.
Таким образом, вы можете выполнить свою задачу следующим образом.
Вариант 1: наиболее оптимизированная версия
Сделайте вашу функцию приостановленной и используйте withContext. Он приостановит вызывающую сопрограмму до тех пор, пока курс не будет выбран.
suspend fun getCourseData(): Course {
return withContext(Dispatchers.IO) {
courseDao.getCourse(globalSelectedCourse)
}
}
// or simpler
suspend fun getCourseData(): Course =
withContext(Dispatchers.IO) {
courseDao.getCourse(globalSelectedCourse)
}
Вариант 2: используйте asyn c и верните Deferred.
// declare scope elsewhere. It is not intended to create scope everytime you want to launch a task
val scope = CoroutineScope(Dispatchers.IO)
// using async at the end of function is a naming scheme by Kotlin recommendation.
fun getCourseDataAsync(): Deferred<Course> =
scope.async {
courseDao.getCourse(globalSelectedCourse)
}
//Now when you call the function, call await(), it is suspending, it will suspend the calling coroutine till the course is fetched.
val course: Course = getCourseDataAsync().await()
Обновление в обновлении OP
Как я также предлагал в комментариях, вы не можете брать блокировку кода за пределами блока сопрограммы. Потому что вы не можете приостановить функцию без приостановки.
Сделайте следующее:
// in fragment
suspend fun getCourseData() : Course {
return lessonDataRepository.getCourseData()
}
viewModel.viewModelScope.launch {
val course = viewModel.getCourseData()
textViewName.text = course.Name
textViewInstructor.text = course.instructor
}