Сопрограммы с запечатанным классом

В моем проекте много операций, которые нужно выполнять одну за другой. Я использовал прослушиватели, но нашел этот учебник Kotlin coroutines на Android, и я хотел изменить свой вызов сервера на более читаемый код. Но я думаю, что мне чего-то не хватает. Приведенный ниже код всегда возвращает ошибку из функции getTime1():

suspend fun getTimeFromServer1() :ResultServer<Long> {
        val userId = SharedPrefsHelper.getClientId()
        return withContext(Dispatchers.IO) {
            val call: Call<ResponseFromServer>? = userId?.let { apiInterface.getTime(it) }
            (call?.execute()?.body())?.run {
                val time:Long? = this.data?.time
                time?.let {
                    Timber.tag("xxx").e("time received it ${it}")// I am getting the right result here
                    ResultServer.Success(it)
                }
                Timber.tag("xxx").e("time received ${time}")
            }
            ResultServer.Error(Exception("Cannot get time"))
        }
    }


fun getTime1() {
        GlobalScope.launch {
            when (val expr: ResultServer<Long> = NetworkLayer.getTimeFromServer1()) {
                is ResultServer.Success<Long> -> Timber.tag("xxx").e("time is ${expr.data}")
                is ResultServer.Error -> Timber.tag("xxx").e("time Error") //I am always get here
            }}
    }
    }

Но если я использую слушателей (getTime()), все работает отлично:

 suspend fun getTimeFromServer(savingFinishedListener: SavingFinishedListener<Long>) {
        val userId = SharedPrefsHelper.getClientId()
        withContext(Dispatchers.IO) {
            val call: Call<ResponseFromServer>? = userId?.let { apiInterface.getTime(it) }
            (call?.execute()?.body())?.run {
                val time:Long? = this.data?.time
                time?.let {
                    Timber.tag("xxx").e("time received it ${it}")
                    savingFinishedListener.onSuccess(it)
                }

            }
            savingFinishedListener.onSuccess(null)
        }
    }

   fun getTime() {
        GlobalScope.launch {
            NetworkLayer.getTimeFromServer(object:SavingFinishedListener<Long>{
                override fun onSuccess(t: Long?) {
                    t?.let {
                        Timber.tag("xxx").e("time here $it") //I am getting the right result
                    }
                }
            })
           }
        }

Заранее благодарю за любую помощь.


person KeitL    schedule 29.01.2021    source источник


Ответы (1)


Последняя строка лямбды неявно является возвращаемым значением этой лямбды. Поскольку у вас нет явных операторов возврата в лямбде withContext, его последняя строка:

ResultServer.Error(Exception("Cannot get time"))

означает, что он всегда возвращает эту ошибку. Вы можете поместить return@withContext прямо перед вашим ResultServer.Success(it), чтобы эта строка кода также возвращалась из лямбда.

Боковое примечание: не используйте GlobalScope.

person Tenfour04    schedule 29.01.2021
comment
Большое спасибо. Оно работает. Но какой контекст я полагаю использовать? - person KeitL; 29.01.2021
comment
Android предоставляет области жизненного цикла для действий / фрагментов и моделей представления (называемых lifecycleScope и viewModelScope соответственно), и они полезны в большинстве случаев. Они автоматически отменяются по окончании соответствующего жизненного цикла. Если вам нужен больший контроль над отменой, вы создаете свою собственную область сопрограммы, используя CoroutineScope(). - person Tenfour04; 29.01.2021
comment
Кстати, если вы используете Retrofit, вы можете удалить оболочку withContext() и использовать await() вместо execute(). await() - это приостановленная версия execute(). - person Tenfour04; 29.01.2021
comment
Немного переписал. Но теперь я получаю сообщение об ошибке: в функции с телом блока ('{...}') требуется выражение "return". - person KeitL; 29.01.2021
comment
приостановить веселье getTimeFromServer3 (): ResultServer ‹Long›? {val userId = SharedPrefsHelper.getClientId () val call: Call ‹ResponseFromServer›? = userId? .let {apiInterface.getTime (it)} (call? .await ()) ?. run {return when (val time: Long? = this.data?.time) {is Long - ›ResultServer.Success ( время) else - ›ResultServer.Error (java.lang.Exception (ndndndn))}}} - person KeitL; 29.01.2021
comment
Вы удалили withContext, но вы также удалили свое return ключевое слово. Вы должны явно использовать ключевое слово return в строках, в которых вы что-то возвращаете. - person Tenfour04; 29.01.2021