Tsudzukeru
@Tsudzukeru

Как заставить главный поток подождать CallBack при использовании Retrofit?

Использую Retrofit, чтобы распарсить сложный Json. Приходится использовать много вложенных циклов в дисериализаторе, поэтому ответ приходит медленнее чем главный поток, возвращает результат из функции.

override fun getVideoInfo(id: String): Video? {
        var video:Video? = Video(null)

      retrofitClient.getVideoInfo(id).enqueue(object : Callback<VideoItemResponse> {
            override fun onFailure(call: Call<VideoItemResponse>, t: Throwable) {
                video = null
                Log.e(VIDEO_ITEM_TAG, "Failure: $t.message" )
            }

            override fun onResponse(
                call: Call<VideoItemResponse>,
                response: Response<VideoItemResponse>
            ) {
                video = response.body()?.item
                Log.e(VIDEO_ITEM_TAG, "Response: ${video}")
            }
        })

        Log.e(VIDEO_ITEM_TAG, "Before return: ${video}")
        return video
    }


Вот лог:
2020-08-18 16:00:25.783 14824-14824/ru.app.yf E/Video item request: Before return: Video(videoId=null, title=null, duration=null, description=null, thumbnails={}, views=null)
2020-08-18 16:00:25.912 14824-14824/ru.app.yf E/Video item request: Response: Video(videoId=Chjs4xqYe0E, title=Влог из США. Я сделал ЭТО!, duration=PT15M37S, description=Регистрируйся в LetyShops и возвращай горящий кэшбэк


Как видно ответ приходит на 129 милисикунды позже. Пытался перед return усыпить поток.

Thread.sleep(1000)
        Log.e(VIDEO_ITEM_TAG, "Before return: ${video}")
        return video


Это не помогло. Как это можно решить?
  • Вопрос задан
  • 272 просмотра
Решения вопроса 1
@snitron
Учуcь программировать на Android, IOS и Unity.
Вы вызываете изначально запрос асинхронно методом enqueue(). Чтобы запустить синхронно - используйте метод execute(). Но, насколько я знаю, Android не даст вам отправить запрос в UI потоке.

P.S.
Я бы пересмотрел архитектуру приложения и вместо возвращения полученного значения в методе (через return), например, прямо в callback'е вызывал бы другой метод, в который уже пришёл бы ответ.

Также можно оформить всё это красивей через RxJava+RxKotlin или корутины.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
alekseyHunter
@alekseyHunter
Android developer
Приходится использовать много вложенных циклов в дисериализаторе

Какие циклы?! Data-классы создали и все. Нужен список, делаете поле List внутри data-класса.

ответ приходит медленнее чем главный поток, возвращает результат из функции.

Да как же можно так код криво писать. Вы вызываете метод, в котором лежит обратный вызов. Пока метод не обработает, он ничего не вернёт. Поэтому при вызове в первый раз вам вернётся ваш объект с Null. В котлине использовать Null?! Его для этого что ли создавали?!

video = response.body()?.item

Что это?? Где проверки на возвращенный сервером код? 400 ошибку(код) вернёт сервер, и вылетит ваша программа!

Thread.sleep(1000)

Нормально, UI поток тормозить. Да и ладно, что приложение не будет реагировать на действия пользователя секунду. Да?!

Ответ: Все действия с сетью делайте асинхронно. Вернул retrofit ответ, проверили его на корректность, вызвали там же метод для обновления ui и сидите радуйтесь.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы