我有以下代码,该代码进行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
    }

07-26 07:48