Каким образом можно "подождать" пока данные не придут, и только после этого возвращать значение?

Рейтинг: 0Ответов: 1Опубликовано: 26.01.2023

В функции которая отправляет запрос и получает данные при помощи Retrofit, return отрабатывает быстрее чем приходят данные с сервера. И таким образом возвращаеться попросту пустое значение.

Вопрос: каким образом можно "подождать" и убедиться что данные успешно пришли, и только затем возвращать значение?

P.S. Я знаю что есть множество способов связанных с корутинами, AsynkTask, Callbacks и прочие. Однако какое решение в данном случае будет наилучшим?

(Приложение базируеться на паттерне MVP, в этом случае Model - это класс RetrofitHelper к которому Presenter обращаеться за данными).

class RetrofitHelper: MainContract.IWeatherModel {

    private val dataList: List<String>? = null

    private var dataTemp: Double? = null
    private var mainData: String? = null
    private var pressureData: Long? = null
    private var humidityData: Long? = null
    private var speedData: Double? = null
    private var sunriseData: Long? = null
    private var sunsetData: Long? = null

    val BASE_URL = "https://api.openweathermap.org/data/2.5/"
    val key = "(key)"
    val units = "metric"


    override fun getWeatherData(city: String): List<String>? {

        val retrofitBuilder = Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(BASE_URL)
            .build()
            .create(APIService::class.java)

        val retrofitData = retrofitBuilder.getData(city, key, units)


        retrofitData.enqueue(object : Callback<Data> {
            override fun onResponse(call: Call<Data>, response: Response<Data>) {
                val responseBody = response.body()!!


                for (i in responseBody.weather) {
                    mainData = i.main

                }
                dataTemp = responseBody.main.temp
                pressureData = responseBody.main.pressure
                humidityData = responseBody.main.humidity
                speedData = responseBody.wind.speed
                sunriseData = responseBody.sys.sunrise
                sunsetData = responseBody.sys.sunset

                val dataList = listOf(
                    dataTemp.toString(),
                    mainData.toString(),
                    pressureData.toString(),
                    humidityData.toString(),
                    speedData.toString(),
                    sunriseData.toString(),
                    sunsetData.toString()
                )

            }

            override fun onFailure(call: Call<Data>, t: Throwable) {
                Log.d("Failure retrofit!", "$t")
            }
        })
        return dataList
    }
}

Ответы

▲ 1

Корутины в языке Kotlin это очень мощный и удобный инструмент для работы с асинхронным кодом. AsyncTask это боль, устаревший способ, не рекомендуется к использованию.

Чтобы начать использовать Retrofit с корутинами, добавьте ключевое слово suspend в сигнатуру метода в интерфейсе Retrofit-сервиса и уберите обертку Call<Data>:

interface APIService {

    @GET("weather?q=Nuremberg")
    suspend fun getData(): Data

}

Теперь, чтобы иметь возможность выполнить suspend-метод и запустить корутину, имплементируйте CoroutineScope в классе MainActivity:

class MainActivity : AppCompatActivity(), CoroutineScope {

    private lateinit var retrofit: RetrofitHelper
    private lateinit var textView: TextView

    override val coroutineContext: CoroutineContext
        get() = Job() + Dispatchers.Main

    ...

    override fun onStart() {
        super.onStart()
        launch {
            val result = retrofit.getWeatherData()
            textView.text = "result: $result"
        }
    }

}

Главное преимущество корутин перед многими другими способами в том, что асинхронный код пишется последовательно. Нет вложенности из коллбеков.

Чтобы лучше разобраться с корутинами, почитайте в документации на русском, что такое coroutine context и dispatchers.