Как заставить компилятор ждать OnCompleteListener Kotlin

#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, как для краткосрочного, так и для долгосрочного запуска.