После исследования Как использовать Fuel с сопрограммой Kotlin , сопрограммы Fuel и https://github.com/kittinunf/Fuel/ (искал awaitStringResponse
), я принял другое решение. Предположим, что у вас есть Kotlin 1.3 с сопрограммами 1.0.0 и Fuel 1.16.0.
Мы должны избегать асинхронных запросов с обратными вызовами и делать синхронные (каждый запрос в его сопрограмме). Скажем, мы хотим показать название страны по коду.
// POST-request to a server with country id.
fun getCountry(countryId: Int): Request =
"map/country/"
.httpPost(listOf("country_id" to countryId))
.addJsonHeader()
// Adding headers to the request, if needed.
private fun Request.addJsonHeader(): Request =
header("Content-Type" to "application/json",
"Accept" to "application/json")
Это дает JSON:
{
"country": {
"name": "France"
}
}
Чтобы декодировать ответ JSON, нам нужно написать класс модели:
data class CountryResponse(
val country: Country,
val errors: ErrorsResponse?
) {
data class Country(
val name: String
)
// If the server prints errors.
data class ErrorsResponse(val message: String?)
// Needed for awaitObjectResponse, awaitObject, etc.
class Deserializer : ResponseDeserializable<CountryResponse> {
override fun deserialize(content: String) =
Gson().fromJson(content, CountryResponse::class.java)
}
}
Затем мы должны создать UseCase или Interactor для синхронного получения результата:
suspend fun getCountry(countryId: Int): Result<CountryResponse, FuelError> =
api.getCountry(countryId).awaitObjectResponse(CountryResponse.Deserializer()).third
Я использую third
для доступа к данным ответа. Но если вы хотите проверить код ошибки HTTP! = 200, удалите third
и позже получите все три переменные (как Triple
переменная).
Теперь вы можете написать метод для печати названия страны.
private fun showLocation(
useCase: UseCaseImpl,
countryId: Int,
regionId: Int,
cityId: Int
) {
GlobalScope.launch(Dispatchers.IO) {
// Titles of country, region, city.
var country: String? = null
var region: String? = null
var city: String? = null
val countryTask = GlobalScope.async {
val result = useCase.getCountry(countryId)
// Receive a name of the country if it exists.
result.fold({ response -> country = response.country.name }
, { fuelError -> fuelError.message })
}
}
val regionTask = GlobalScope.async {
val result = useCase.getRegion(regionId)
result.fold({ response -> region = response.region?.name }
, { fuelError -> fuelError.message })
}
val cityTask = GlobalScope.async {
val result = useCase.getCity(cityId)
result.fold({ response -> city = response.city?.name }
, { fuelError -> fuelError.message })
}
// Wait for three requests to execute.
countryTask.await()
regionTask.await()
cityTask.await()
// Now update UI.
GlobalScope.launch(Dispatchers.Main) {
updateLocation(country, region, city)
}
}
}
В build.gradle
:
ext {
fuelVersion = "1.16.0"
}
dependencies {
...
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0'
// Fuel.
//for JVM
implementation "com.github.kittinunf.fuel:fuel:${fuelVersion}"
//for Android
implementation "com.github.kittinunf.fuel:fuel-android:${fuelVersion}"
//for Gson support
implementation "com.github.kittinunf.fuel:fuel-gson:${fuelVersion}"
//for Coroutines
implementation "com.github.kittinunf.fuel:fuel-coroutines:${fuelVersion}"
// Gson.
implementation 'com.google.code.gson:gson:2.8.5'
}
Если вы хотите работать с coroutines
и Retrofit
, пожалуйста, прочитайте https://medium.com/exploring-android/android-networking-with-coroutines-and-retrofit-a2f20dd40a83 (или https://habr.com/post/428994/ на русском языке).