如何适当地使可重用的类使用改型来捕获响应数据?

时间:2019-01-23 11:16:05

标签: android kotlin retrofit2

我是Android开发的新手,我正在尝试从服务器获取数据。通用的JSON响应结构将是这样

{
    "success": "1",
    "data": [
        {
            "customers_id": 4,
            "customers_gender": "0",
            "customers_firstname": "TES IOS",
            "customers_lastname": "TES IOS",
            "customers_dob": "2018-12-27",
            "email": "TES002@email.com",
            "user_name": "TES002",
            "customers_default_address_id": 0,
            "customers_telephone
         },
    "message": "Successfully get user data from server"
}

“成功”和“消息”字段将相同(始终为字符串)。但是对于其他请求调用,“数据”可以不同。它可以发送用户数据,存储数据或产品数据,甚至产品阵列/产品列表。

所以我想制作通用的可重用类来捕获该JSON响应。该类将是这样,我将“数据”设置为Any,然后将其强制转换回User对象:

class ServerData(successStatus: Int, data: Any, message: String) {

    val isSuccessfull : Boolean
    val data : Any
    val message : String


    init {
        isSuccessfull = successStatus != 0
        this.data = data
        this.message = message
    }


}

界面是这样的:

interface LakuinAPI {

    @FormUrlEncoded
    @POST("processlogin")
    fun performLogin(
        @Field("kode_customer") outletCode: String,
        @Field("password") password: String
    ): Call<ServerData>


}

然后在活动中使用它,如下面的代码:

private fun sendLoginDataToServer(outletCode: String, password: String) {

        val call = lakuinAPI.performLogin(outletCode,password)

        call.enqueue(object: Callback<ServerData> {

            override fun onFailure(call: Call<ServerData>, t: Throwable) {
                Toast.makeText(this@LoginActivity,t.localizedMessage,Toast.LENGTH_LONG).show()
            }

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

                if (!response.isSuccessful) {
                    Toast.makeText(this@LoginActivity,"Code: " + response.code(),Toast.LENGTH_LONG).show()
                    return
                }

                val lakuinServerData = response.body()
                val userList = lakuinServerData?.data as List<User> // the error in here
                val userData = userList.first() // the error in here
                println(userData)

            }

        })


    }

但我收到错误消息:

  

java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap   无法转换为com.ssss.lakuinkotlin.Model.User

我在错误位置上方的代码中给出注释。我不知道为什么会这样。

老实说,如果这是从一般响应JSON(如上面的JSON)中捕获用户数据的正确方法,我不是。有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

您可以使用泛型来实现

class Response<Data> constructor() : ResponseSimple() {
   @SerializedName(FIELD_DATA)
   var data: Data? = null
   private constructor(data: Data) : this() {
       this.data = data
   }
   companion object {
       const val FIELD_SUCCESS = "success"
       const val FIELD_ERROR = "error"
       const val FIELD_DATA = "data"
       const val FIELD_MESSAGE = "message"

       @JvmStatic
       fun <Data> create(data: Data): Response<Data> {
          return Response(data)
       }
   }
}

ResponseSimple

open class ResponseSimple {

@SerializedName(Response.FIELD_ERROR)
var error: String = ""

@SerializedName(Response.FIELD_SUCCESS)
var succes: Boolean = false

@SerializedName(Response.FIELD_MESSAGE)
var message:String = ""
}

然后api响应应该为Call<Response<ServerData>>

关于ClassCastException,您不能仅使用ServerDataUser转换为as。 您需要使用Call<Response<ArrayList<User>>>或创建类转换器。

答案 1 :(得分:0)

尝试替换此行:

val userList = lakuinServerData?.data as List<User> 

具有:

val userList = lakuinServerData?.data as new TypeToken<List<User>>(){}.getType()