我有以下代码,该代码进行API调用以从邮政编码获取地址。
fun getAddressFromPostCode(postCode: String): List<Address>{
val trimmedPostCode = postCode.replace("\\s".toRegex(),"").trim()
val dataBody = JSONObject("""{"postcode":"$trimmedPostCode"}""").toString()
val hmac = HMAC()
val hmacResult = hmac.sign(RequestConstants.CSSecretKey, dataBody)
val body = JSONObject("""{"data":$dataBody, "data_signature":"$hmacResult"}""")
val url = RequestConstants.URL
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()
val api:GetAddressAPIService = retrofit.create(GetAddressAPIService ::class.java)
var myList = emptyList<Address>()
val myCall: Call<GetAddressResponse> = api.getAddress(body)
myCall.enqueue(object : Callback<GetAddressResponse> {
override fun onFailure(call: Call<GetAddressResponse>?, t: Throwable?) {
Log.d("RegistrationInteractor", "Something went wrong", t)
Log.d("RegistrationInteractor", call.toString())
}
override fun onResponse(call: Call<GetAddressResponse>?, response: Response<GetAddressResponse>?) {
// Success response
myList = response!!.body()!!.addresses
}
})
return myList
}
这是我打电话的地方:interface GetAddressAPIService {
@Headers("Accept: application/json; Content-Type: application/json")
@POST("postcode_search.php")
fun getAddress(@Body dataBody: JSONObject): Call<GetAddressResponse>
}GetAddressResponse看起来像这样,似乎是正确的:
数据类GetAddressResponse(
val成功:Int,
val地址:列表
)
数据主体为{“data”:{“postcode”:“M130EN”},“data_signature”:“长数据签名”},当我在Postman中运行时,我会得到一个地址列表,但是当我在应用程序中运行它时我得到200 OK响应,但没有地址。有什么想法吗?
最佳答案
您的代码正在返回,但是enqueue
是异步的,因此不能保证在返回之前发生。如果您阅读enqueue
,则会在其中有一个回调,这意味着在准备好之后,它将继续call
back
,因为它是一个HTTP请求,所以需要一些时间,并且在返回后完成。
您有2种选择,将Callback<GetAddressResponse>
添加为参数,或将任何其他回调添加为参数,或者可以使其挂起。
打回来
协程是现在推荐的操作方式,因此不再被认为是一种好习惯。
fun getAddressFromPostCode(postCode: String, callback: Callback<GetAddressResponse): List<Address>{
...
myCall.enqueue(callback)
}
调用类必须实现回调并将其作为参数传递。您可以使用lambda来制作更酷的Kotlin方式:fun getAddressFromPostCode(postCode: String, callback: (items: List<Address> -> Unit))
...
override fun onResponse(call: Call<GetAddressResponse>?, response: Response<GetAddressResponse>?) {
callback(response...)
}
}
这样就可以使调用类以这种方式使用它yourClass.getAddressFromPostCode(postalCode) { -> items
//do your thing with items
}
协程您可以使用暂停功能将其转换为线性代码:
//make it return optional to know if it was failure
suspend fun getAddressFromPostCode(postCode: String): List<Address>? {
...
return try {
myCall.invoke().result?.body()
} catch (e: Exception) {
null
}
}
然后调用类必须像这样使用它: lifeCycleScope.launch {
val addresses = yourClass.getAddressFromPostCode(postalCode)
//do your thing on the UI with the addresses maybe pass it to an adapter
}