【问题标题】:Using Retrofit in Kotlin在 Kotlin 中使用改造
【发布时间】:2018-08-31 11:25:16
【问题描述】:

我正在尝试在 kotlin 中使用改造来访问 api

这是我的 DoinBackGround 方法

private fun doinBackground() {

    Utility.printMessage("in do in  background.....")
    try {
        val hdr = HashMap<String, String>()
        hdr.put("x-csrf-token", Utility.getToken(this.context!!))

        val apiInterface = ApiCallRetrofit.getClient(this.mCrypt!!)!!.create(ApiInterface::class.java)



        if (what.equals(0)) {
            val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), getQuery(para))
            print("header...")
            call = apiInterface.hitApi(url, hdr, body)


        } else if (what.equals(1)) {

            val imgPart = ArrayList<MultipartBody.Part>()
            if (files != null) {
                if (files.size > 0) {
                    for (i in files.indices) {
                        imgPart.add(preparePart("image/*", "document_file[" + files.get(i).key + "]", files.get(i).file))
                    }
                }
                call = apiInterface.hitApiImage(url, hdr, getMap(para), imgPart)

            }



            call?.enqueue(object : Callback<StandardReposnse> {
                override fun onResponse(call: Call<StandardReposnse>, response: Response<StandardReposnse>) {
                    try {

                        Utility.printMessage("messege...." + response.body().message)
                        val resp = Gson().toJson(response.body())
                        Utility.printMessage("Response :$resp")
                        Utility.longLogPrint(response.body().data, "Full response : ")
                        Utility.printMessage("Error : " + Gson().toJson(response.errorBody()))
                        onPostExecute(Parseresponce(response.body()))
                    } catch (e: Exception) {
                        Parseresponce(null)

                        e.printStackTrace()
                    }

                }

                override fun onFailure(call: Call<StandardReposnse>, t: Throwable) {
                    t.printStackTrace()
                    if (progressDialog != null) {
                        progressDialog?.dismiss()
                    }
                    Parseresponce(null)
                }
            })
        }

    } catch (e: Exception) {
        e.printStackTrace()
    }


}

这是我定义所有 POST 方法的界面

@POST
abstract fun hitApi(@Url api: String, @HeaderMap header: Map<String, Any>, @Body body: RequestBody): Call<StandardReposnse>


@POST
fun hitApiNoHeader(@Url api: String, @Body requestBody: RequestBody): Call<StandardReposnse>

@POST
fun test(@Url api: String, @HeaderMap headerMap: Map<String, String>, @Body requestBody: RequestBody): Call<JSONObject>

@Multipart
@POST
fun hitApiImage(@Url api: String, @HeaderMap headerMap: Map<String, String>, @PartMap bodyMap: Map<String, RequestBody>, @Part images: List<MultipartBody.Part>): Call<StandardReposnse>

每当我尝试使用 Api 时,我都会收到以下异常:

java.lang.IllegalArgumentException: Parameter type must not include a type variable or wildcard: java.util.Map<java.lang.String, ?> (parameter #2)
for method ApiInterface.hitApi
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:720)
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:711)
at retrofit2.ServiceMethod$Builder.parameterError(ServiceMethod.java:729)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:193)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166)

这是doinbackground方法发生异常的那一行

call = apiInterface.hitApi(url, hdr, body)

我在 RequestBody 之前尝试了@JvmSuppressWildcards 但它没有用,任何人都可以建议这里的实际问题是什么,而且虽然我使用了 print() 函数,但日志中没有打印任何内容,我应该使用 LOG.d 吗?

【问题讨论】:

    标签: kotlin gson retrofit


    【解决方案1】:

    这里我有完整的例子。

    这个依赖添加在gradle中

    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    annotationProcessor 'com.squareup.retrofit2:retrofit:2.5.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    

    现在在这里创建 ApiClient.kt 文件

    object ApiClient {
    
    val BASE_URL = "http://yourwebsite/services/"
    private var retrofit: Retrofit? = null
    
    val client: Retrofit
        get() {
            if (retrofit == null) {
                retrofit = Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
            }
            return retrofit!!
        }
    

    }

    现在创建 APIInterface.kt

    @FormUrlEncoded
    @POST("users/login")
    fun POST_LOGIN(
            @Field("imei_number") imei_number: String,
            @Field("device_token") device_token: String,
            @Field("mobile") mobile: String,
            @Field("password") password: String
    ): Call<LoginResponse>
    
    @GET("general/init-data")
    fun GENERAL_MODULE(
            @Header("Authorization") auth_key: String
    ): Call<InitResponse>
    
    @GET("event-gallery/list")
    fun GET_Event_GALLERY(
            @Header("Authorization") auth_key: String
    ): Call<EventListResponse>
    
    @GET("event-gallery/photo-list")
    fun GET_Event_GALLERY_PHOTO(
            @Header("Authorization") auth_key: String,
            @Query("id") id: Int
    ): Call<EventGallerListResponse>
    

    如果令牌的任何标头使用@Header,并且当调用@GET 时参数使用@Query 和@Post 时@Fields

    现在响应文件

    data class EventListResponse(
        @SerializedName("success")
        var success: Boolean,
        @SerializedName("data")
        var data: EventgalleryModel?,
        @SerializedName("server_error"),
        @SerializedName("eventgallery")
        var eventgallery: ArrayList<EventListData>
        var server_error: Boolean,
        @SerializedName("message")
        var message: String
    

    )

    然后创建Response的Model类

    现在是活动代码的时候了

    private fun loadData() {
        card_progress.visibility = View.VISIBLE
        val apiService = ApiClient.client.create(ApiInterface::class.java)
        val call =
            apiService.GET_FEE_INSTALMENT_LIST(PreferenceManager.getAuthKey(this@FeesInstalmentActivity)!!)
        call.enqueue(object : Callback<FeeInstalmentListResponse> {
            override fun onResponse(
                call: Call<FeeInstalmentListResponse>,
                response: Response<FeeInstalmentListResponse>
            ) {
                card_progress.visibility = View.GONE
                val data = response.body()!!.data
                if (response.code() == 200 && data != null) {
                    if (response.body()!!.server_error) {
                        txt_no_data_fee.visibility = View.VISIBLE
                        txt_no_data_fee.text = response.body()!!.message
                    } else {
                        Log.e("data", data.toString())
                        if (data != null && data.feesinstalment.isEmpty()) {
                            txt_no_data_fee.visibility = View.VISIBLE
                        } else {
                            txt_no_data_fee.visibility = View.GONE
                            adapter!!.setItem(data.feesinstalment)
                        }
                    }
                } else if (response.code() == 401) {
                    PreferenceManager.removePref(this@FeesInstalmentActivity)
                    startActivity(
                        Intent(this@FeesInstalmentActivity, LoginActivity::class.java)
                            .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
                    )
                    finish()
                } else {
                    Toast.makeText(
                        this@FeesInstalmentActivity,
                        R.string.somethingWrong,
                        Toast.LENGTH_SHORT
                    ).show()
                }
    
    
            }
    
            override fun onFailure(call: Call<FeeInstalmentListResponse>, t: Throwable) {
                card_progress.visibility = View.GONE
                Log.e("onFailure", t.message)
                txt_no_data_fee.visibility = View.VISIBLE
            }
        })
    }
    

    适配器

    class FeeInstalmentAdapter(
        private val context: Context,
        private var items: ArrayList<FeeInstalmentListData>
    

    ) : RecyclerView.Adapter() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(LayoutInflater.from(context).inflate(R.layout.row_fees_instalment_item, parent, false))
    }
    
    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.due_date.text = DateHelper.parseData(items[position].due_date!!, "yyyy-MM-dd", "dd MMM yyyy")
        holder.instalment_title.text = items[position].instalment_title
        if (items[position].paid_date == null) {
            holder.paid_text.visibility = View.GONE
            holder.paid_date.text = context.resources.getString(R.string.UnPaid)
            holder.paid_date.setTextColor(Color.parseColor("#DC143C"))
        } else {
            holder.paid_date.text = DateHelper.parseData(items[position].due_date!!, "yyyy-MM-dd", "dd MMM yyyy")
            holder.paid_date.setTextColor(Color.parseColor("#58A259"))
        }
        //holder.paid_date.text = items[position].paid_date
        holder.amount.text = "Rs. " + items[position].amount
        holder.amount.setTextColor(Color.parseColor("#ED7136"))
    
    }
    
    
    override fun getItemCount(): Int {
        return items.size
    }
    
    override fun getItemId(position: Int): Long {
        return position.toLong()
    }
    
    override fun getItemViewType(position: Int): Int {
        return position
    }
    
    fun setItem(holidays: ArrayList<FeeInstalmentListData>) {
        items = holidays
        notifyDataSetChanged()
    }
    
    
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val due_date = view.due_date
        val instalment_title = view.instalment_title
        val paid_date = view.paid_date
        val amount = view.amount
        val paid_text = view.paidText
    }
    

    }

    【讨论】:

      【解决方案2】:

      按照下面提到的方式调用它。

        val callWeather = NetworkUtils.getApiInterface().getWeatherResponse("03a7949903004a0bb2590633181104", "1.909,45.909", 7)
      
                  callWeather.enqueue(object : Callback<APIXUResponse> {
                      override fun onResponse(call: Call<APIXUResponse>, response: Response<APIXUResponse>) {
                          var api :APIXUResponse? = response.body()
                      }
      
                      override fun onFailure(call: Call<APIXUResponse>, t: Throwable) {
      
                      }
                  })
      

      【讨论】:

        【解决方案3】:

        您使用过:

        @POST
        abstract fun hitApi(@Url api: String, @HeaderMap header: Map<String, Any>, @Body body: RequestBody): Call<StandardReposnse>
        

        例外是:

        Parameter type must not include a type variable or wildcard: java.util.Map<java.lang.String, ?> (parameter #2)
        

        而你的 hitApi #2 参数实际上使用了通配符:

        @HeaderMap header: Map<String, ?>
        

        尝试指定参数(只需将 Any 更改为 String)。无论如何,您可能不会在请求标头中放置除 String 之外的任何对象。

        【讨论】:

        • 我也试过这个解决方案,但得到同样的错误
        猜你喜欢
        • 2020-08-26
        • 1970-01-01
        • 1970-01-01
        • 2018-05-03
        • 1970-01-01
        • 1970-01-01
        • 2020-09-08
        • 1970-01-01
        • 2018-09-09
        相关资源
        最近更新 更多