Каким образом можно "подождать" пока данные не придут, и только после этого возвращать значение?
В функции которая отправляет запрос и получает данные при помощи 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.