【问题标题】:how to handle two different Retrofit response in Kotlin?如何在 Kotlin 中处理两种不同的改造响应?
【发布时间】:2020-09-23 03:36:24
【问题描述】:

我曾尝试在 here 中的 java 中阅读此类似线程 所以我在那里尝试接受的答案,但它不起作用。这是我的问题

我将从端点获得两个不同的 JSON 响应。如果我成功获取 Restaurant 数据,JSON 将是这样的

{

    "R": {
       "has_menu_status": {
       "delivery": -1,
       "takeaway": -1
        },
       "res_id": 18941862,
       "is_grocery_store": false
    },
    "id": "18941862",
    "name": "Pizza Maru",
    "url": "https://www.zomato.com/jakarta/pizza-maru-1-thamrin?utm_source=api_basic_user&utm_medium=api&utm_campaign=v2.1",
    "location": {
        "address": "Grand Indonesia Mall, East Mall, Lantai 3A, Jl. M.H. Thamrin No. 1, Thamrin, Jakarta",
        "locality": "Grand Indonesia Mall, Thamrin",
        "city": "Jakarta",
        "city_id": 74,
        "latitude": "-6.1955810000",
        "longitude": "106.8213770000",
        "zipcode": "",
        "country_id": 94,
        "locality_verbose": "Grand Indonesia Mall, Thamrin, Jakarta"
    },
    "switch_to_order_menu": 0,
    "cuisines": "Pizza",
    "timings": "10 AM to 10 PM",
    "average_cost_for_two": 180000,
    "price_range": 3,
    "currency": "IDR",
    "thumb": "https://b.zmtcdn.com/data/pictures/chains/2/18941862/403aa36cb046e86a694e7989bb7cd545.jpg?fit=around%7C200%3A200&crop=200%3A200%3B%2A%2C%2A",
    "has_online_delivery": 0,
    "is_delivering_now": 0,
    "store_type": "",
    "phone_numbers": "021 3108656",
    
}

如果我发送无效的餐厅 ID,我将收到如下错误 JSON 响应:

{
    "code": 404,
    "status": "Not Found",
    "message": "Not Found"
}

这是我制作的数据类

data class Restaurant (

    @SerializedName("id")
    val id : Int = 0,

    @SerializedName("name")
    var name : String = "",

    @SerializedName("url")
    val url : String = "",

    @SerializedName("location")
    val location : Location = Location(),

    @SerializedName("currency")
    val currency : String = "",

    @SerializedName("phone_numbers")
    val phone_numbers : String = "",

    @SerializedName("thumb")
    val thumbnail : String = ""

)

成功响应

data class Location (

    @SerializedName("address")
    val address : String = "",

    @SerializedName("city")
    val city : String = "",

    @SerializedName("latitude")
    val latitude : Double = 0.0,

    @SerializedName("longitude")
    val longitude : Double = 0.0,

    @SerializedName("zipcode")
    val zipcode : String = ""

)
    

用于错误响应

data class ErrorResponse (

    val code : Int,
    val status : String,
    val message : String
)
         

这是我的改造界面。想法是,我先将其转换为 Any,然后我将向下转换为 RestaurantZomatoErrorResponse

interface RestaurantAPI {

    @Headers("user-key: $USER_KEY_ZOMATO")
    @GET("restaurant")
    fun getRestaurantDetail(
        @Query("res_id") id: Int
    ): Call<Any>
}

这是错误:

所以我像这样使用我的改造

        val call = restaurantService.getRestaurantDetail(restaurantID)

        call.enqueue(object: Callback<Any>{

            override fun onResponse(call: Call<Any>, response: Response<Any>) {

                if (response.isSuccessful) {

                    // this line is executed

                    Log.d("checkxxx","${response.body()}")

                    val restaurantData = response.body() as Restaurant // <-- but Error while casting Any to Restaurant in here
                    restaurant.postValue(restaurantData)
                } 
                
            }


        })

我的应用程序在该行崩溃。但实际上我可以成功获取数据,但我无法将其投射到餐厅。

这里是我的 response.body() 的 logcat

这里出了什么问题?

或者也许有比这个更好的方法

【问题讨论】:

  • 一个很酷的方法是将这两个响应组合在一起并创建一个包含所有可能响应的data class。然后检查响应代码并在此基础上进行转换。
  • 顺便说一句,我没有看到来自 logcat 的错误。如果可以的话,添加它。
  • @MohammadZarei 我在底部添加了我的 logcat 的屏幕截图

标签: android kotlin retrofit2


【解决方案1】:

我终于可以使用下面的代码解决我的问题了

        val call = restaurantService.getRestaurantDetail(restaurantID)

        call.enqueue(object: Callback<Any>{

            override fun onResponse(call: Call<Any>, response: Response<Any>) {


                if (response.isSuccessful) {


                    val gson = Gson()
                    val restaurantData = gson.fromJson(gson.toJson(response.body()), Restaurant::class.java)
                    

                } else {

                    val errorBody = response.errorBody() ?: return
                    val type = object : TypeToken<ErrorResponse>() {}.type
                    val errorResponse: ErrorResponse? = gson.fromJson(errorBody.charStream(), type)
                    val errorMessage = errorResponse?.message ?: "Unknown Error"

                    

                }
            }


        })

不要忘记将接口设置为 Any like this

interface RestaurantAPI {

    @Headers("user-key: $USER_KEY_ZOMATO")
    @GET("restaurant")
    fun getRestaurantDetail(
        @Query("res_id") id: Int
    ): Call<Any> // <---- set to Any like this
}

就我而言,我有成功响应和错误响应。所以我需要像这样分开它。

但如果您有 2 个成功的响应但它具有不同的 JSON,那么您需要在我上面的代码中对 restaurantData 执行空值检查,如果为空,则将其映射到另一个 POJO。

【讨论】:

    【解决方案2】:

    您应该使用 gson 将 json 转换为对象 https://github.com/google/gson

    Example 
    val gson = Gson();
    val  jsonInString = "{\"userId\":\"1\",\"userName\":\"Yasir\"}";
    val user = gson.fromJson(jsonInString, User.class);
    

    【讨论】:

    • 如何获得 jsonInString ?我试图将 response.body 向下转换为 String,因为 response.body 是 Any?但它不起作用。似乎 reponse.body 不是字符串
    • 如果我记录 response.body() 这是一个 Any? ,会是这样的i.stack.imgur.com/Gzn5n.png
    猜你喜欢
    • 2018-12-16
    • 2021-12-28
    • 1970-01-01
    • 2018-07-07
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多