#android #multithreading #kotlin
#Android #многопоточность #котлин
Вопрос:
Я использую эту функцию, чтобы получить местоположение пользователей, а затем вернуть местоположение другой функции в качестве аргумента. Однако компилятор не ожидает завершения OnComleteListener до того, как он вернет null, поскольку переменная location была инициализирована как null.
Кто-нибудь может помочь мне заставить компилятор ждать результата определения местоположения от слушателя? Я получаю местоположение с устройства, поскольку могу распечатать его в текстовом виде.
Вот функция, на которую я ссылаюсь:
@SuppressLint("MissingPermission", "SetTextI18n")
fun getLastLocation(): Location? {
var holder: Location? = null
Log.e(TAG,"CALLED")
if(CheckPermission()) {
if(isLocationEnabled()) {
fusedLocationProviderClient.lastLocation.addOnCompleteListener {task ->
var location = task.result
Log.e(TAG,"Location: $location")
if(location == null) {
getNewLocation()
} else {
holder = location
Log.e(TAG, "Holder1 = $holder")
locationText.text = "Your current coordinates are :nLat: " location.latitude " ; Long: " location.longitude
}
}
Log.e(TAG, "Holder2 = $holder")
} else {
Toast.makeText(this, "Please enable your location service", Toast.LENGTH_LONG).show()
}
} else {
RequestPermission()
}
Log.e(TAG, "Holder3 = $holder")
return holder
}
Комментарии:
1. используйте
suspendCoroutine
. Если вы хотите заблокировать, вы можете запустить его подrunBlocking {}
2. Не могли бы вы показать мне пример того, как это реализовать, пожалуйста?
Ответ №1:
Как уже отмечалось, вы можете использовать suspendCoroutine
для асинхронного (приостановленного) ожидания завершения.
suspend fun <T> Task<T>.await(): T {
if (isComplete) {
val e = exception
return if (e == null) {
if (isCanceled) {
throw CancellationException(
"Task $this was cancelled normally.")
} else {
result
}
} else {
throw e
}
}
return suspendCancellableCoroutine { cont ->
addOnCompleteListener {
val e = exception
if (e == null) {
if (isCanceled) cont.cancel() else cont.resume(result)
} else {
cont.resumeWithException(e)
}
}
}
}
// Usage:
try{
val location = fusedLocationProviderClient.lastLocation.await()
} catch(e:Exception){
//handle exception
}
// do something with location, that should be executed after location has fetched
Если вы не запускаете код для ожидания внутри сопрограммы, вы можете обернуть код с помощью runBlocking для синхронного ожидания (блокируя текущий поток).
val location = runBlocking { fusedLocationProviderClient.lastLocation.await() }
// do something with location, that should be executed after location has fetched
Комментарии:
1. Спасибо. У меня проблема с функцией await(), в ней говорится о неразрешенной ссылке T
2. @Lyndon2309 ах, извините, общее объявление отсутствовало при объявлении функции, просто исправил это.
3. Большое тебе спасибо, брат! Ты меня кое-чему научил!
4. Теперь он жалуется на возобновление? Говоря следующее: Ошибка вывода типа: не удается вывести параметр типа T во встроенном fun <T> Продолжение<T # 1 (параметр типа kotlin.coroutines.resume)>.resume (значение: T # 1) : Единица измерения
5. @Lyndon2309 что это говорит? Для меня это выглядит нормально: imgur.com/a/phqTKM0
Ответ №2:
Я предлагаю лучше использовать жизненный цикл Activity. Это одно из основных, но фундаментальных свойств приложения.
Это показывает, как onCreate, OnStart, onPause, onResume и т.д. работает. Существует множество руководств, показывающих, как это можно использовать, и это очень легко понять. И я думаю, что это намного удобнее, чем OnCompleteListener, как для краткосрочного, так и для долгосрочного запуска.