Обратный вызов получить ответ Sync kotlin

Я пытаюсь получить ответ обратного вызова в режиме синхронизации, потому что значение ответа необходимо для работы всего приложения, без этого значения (токена) я не могу продолжать использовать приложение. Это мой объект-компаньон внутри интерфейса модернизации. Мне нужно установить токен перед созданием клиента.

Что я делаю не так?

РЕДАКТИРОВАТЬ :

Я ставлю как это Журналы, как вы пишете:

companion object {

    private var mToken: String = ""

    fun create(activity: Activity): MyPhoneInterface {
        Log.d("tokenMyPhoneInterface", activity.localClassName)
        getToken(activity)
        Log.d("tokenMyPhoneInterface", "client token $mToken")

        val client = OkHttpClient.Builder()
                .addInterceptor { chain ->
                    val request = chain.request().newBuilder()
                            .addHeader("Authorization", mToken).build()
                    chain.proceed(request)
                }.build()

        val retrofit = Retrofit.Builder()
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .baseUrl(BuildConfig.API_HOST)
                .build()

        return retrofit.create(MyPhoneInterface::class.java)
    }

    private fun getToken(activity: Activity) {
        if (!activity.isFinishing && isJwtExpired(mToken)){
            val latch = CountDownLatch(1)
            (LoginManager(activity)).getToken(true, object : ServiceCallback<String> {
                override fun success(token: String) {
                    Log.d("tokenMyPhoneInterface", "token $token")
                    mToken = token
                    latch.countDown()
                }
                override fun failure(serviceError: ServiceError) {
                    Log.d("tokenMyPhoneInterface", serviceError.errorMessage)
                    latch.countDown()
                }
            })
            Log.d("tokenMyPhoneInterface", "before await ")
            latch.await()
            Log.d("tokenMyPhoneInterface", "after await")
        }
    }
}

Но я система заблокирована в latch.await (), а журналы:

05-14 18: 19: 00.127 848-848 / com.italy.myphone D / tokenMyPhoneInterface: view.splash.activity.Splash 05-14 18: 19: 00.131 848-848 / com.italy.myphone D / tokenMyPhoneInterface: перед ожиданием

ИЗМЕНИТЬ ответ2:

sealed class TokenResult {
class Success(val token: String) : TokenResult()
class Error(val serviceError: ServiceError) : TokenResult()}



suspend fun getToken(activity: Activity): TokenResult {
return suspendCancellableCoroutine { continuation ->
    (LoginManager(activity)).getToken(true, object : ServiceCallback<String> {
        override fun success(token: String) {
            continuation.resume(TokenResult.Success(token))
        }

        override fun failure(serviceError: ServiceError) {
            continuation.resume(TokenResult.Error(serviceError))
        }
    })
}}

И вот как я пытаюсь вызвать функцию приостановки:

companion object {
    fun create(activity: Activity): MyPhoneInterface{
        Log.d("tokenMyPhoneInterface", activity.localClassName)


        var token = runBlocking {
            return@runBlocking getToken(activity)
        }


        Log.d("tokenMyPhoneInterface", "obtained token")

        Log.d("tokenMyPhoneInterface", "client token $tokenResult")

        val client = OkHttpClient.Builder()
                .addInterceptor { chain ->
                    val request = chain.request().newBuilder()
                            .addHeader("Authorization", "").build()
                    chain.proceed(request)
                }.build()

        val retrofit = Retrofit.Builder()
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .baseUrl(BuildConfig.API_HOST)
                .build()

        return retrofit.create(MyPhoneInterface::class.java)
    }
}

Это внутри интерфейса, и это код, который я использую для вызова объекта интерфейса / компаньона в действии:

    private val mMyPhoneInterface by lazy {
    MyPhoneInterface.create(activity)
}
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
3 954
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вам не следует использовать latch.count. Он равен 1, а latch.count > 1 - это false. Затем ваша функция возвращается. Просто используйте latch.await(), и он будет ждать одного из обратных вызовов.

Извините, если я ошибаюсь, у меня недостаточно репо для комментариев.

Спасибо, но это не работает, я меняю его, как вы пишете, но системный блок в ожидании без каких-либо действий ... Я также публикую это в своем ответе

Alessandro Candon 14.05.2018 16:28

@AlessandroCandon Тогда можете ли вы обновить код и предоставить отформатированные журналы?

Alexandr 14.05.2018 16:30

Спасибо) Тогда похоже, что ваша функция в действии не вызывает методы обратного вызова. Я имею в виду, что проблема не в этом коде.

Alexandr 14.05.2018 16:35

Странно, почему активность это заблокирует? Я не думаю, что это возможно, потому что я только жду ответа обратного вызова, чтобы создать клиента. Вы знаете какой-нибудь обходной путь?

Alessandro Candon 14.05.2018 16:56

@AlessandroCandon Можете ли вы просто вызвать один из ваших методов обратного вызова в методе getToken() и вернуться? Это должно оставить некоторую информацию в logcat. И выложить несколько логов после звонка await().

Alexandr 14.05.2018 17:37

Лучший способ получить ответ обратного вызова в режиме синхронизации - это использовать Сопрограммы и функция suspendCancellableCoroutine В вашем случае у вас может быть эта функция:

suspend fun getToken(activity: Activity): TokenResult {
    return suspendCancellableCoroutine { continuation ->
        (LoginManager(activity)).getToken(true, object : ServiceCallback<String> {
            override fun success(token: String) {
                continuation.resume(TokenResult.Success(token))
            }

            override fun failure(serviceError: ServiceError) {
                continuation.resume(TokenResult.Error(serviceError))
            }
        })
    }
}

sealed class TokenResult {
    class Success(val token: String) : TokenResult()
    class Error(val serviceError: ServiceError) : TokenResult()
}

А в вашем activity.onCreate:

override fun onCreate(savedInstanceState: Bundle?) = runBlocking {
    super.onCreate(savedInstanceState)
    val tokenResult = getToken(this)
    if (tokenResult is Error){
        finish()
        return@runBlocking
    }

    //create client here with tokenResult.token value
}

Попробуйте и дайте мне знать ...

Обновлено: В этом примере я использую runBlocking, потому что getToken - это функция приостановки. В вашем собственном коде вы должны обрабатывать эту логику вне деятельности.

Обновлено: Чтобы включить сопрограммы в вашем проекте, добавьте следующие строки в свой файл gradle:

dependencies {
//other dependencies
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5"
}
kotlin {
    experimental {
        coroutines "enable"
    }
}

Мне нужно что-то импортировать? потому что студия Android выдает мне ошибку о suspendCancellableCoroutine

Alessandro Candon 14.05.2018 20:30

Разве не используются сопрограммы для обратной блокировки вызовов? Сначала вы настраиваете все для красивого асинхронного кода, а затем оборачиваете его в runBlocking. Он ничем не лучше CountDownLatch.

Marko Topolnik 14.05.2018 20:48

Использование функции runBlocking в этом примере просто для вызова функций приостановки прямо внутри функции onCreate (). Просто чтобы попробовать код.

Fredy Mederos 14.05.2018 21:56

А если я хочу, чтобы пользователь getToken не участвовал в активности? И когда я создаю клиента, я хочу вернуть его другой функции?

Alessandro Candon 14.05.2018 22:10

Просто вызовите getToken, когда захотите, в другой функции приостановки или внутри сопрограммы. Чтобы узнать больше о сопрограммах, прочтите это: github.com/Kotlin/kotlinx.coroutines/blob/master/…

Fredy Mederos 14.05.2018 22:29

Я добавляю ваше решение, но оно не работает, оно заблокировано на белой странице

Alessandro Candon 15.05.2018 11:16

Это связано с тем, что getToken долго отвечает, а активность блокируется функцией onCreate. Вы должны реализовать все это вне деятельности.

Fredy Mederos 15.05.2018 17:07
Ответ принят как подходящий

В конце я использую JavaRx для синхронизации обратного вызова .. это фрагмент.

fun getToken(loginManager: LoginManager): String {
return Single
        .create(SingleOnSubscribe<String> { emitter ->
            loginManager.getToken(object : TokenSimpleCallback {
                override fun onSuccess(token: String) {
                    emitter.onSuccess(token)
                }

                override fun onFailure(loginServiceError: LoginServiceError) {
                    emitter.onError(Throwable(loginServiceError.toString()))
                }
            })
        }).blockingGet()}

Другие вопросы по теме