使用 Retrofit 和 Kotlin 从 API 获取内容

Fetch content from API with Retrofit and Kotlin

我无法从我的 API 获取数据,但它与 Insomnia

完美配合

JSON 来自我的 API

{
  "count": 4,
  "products": [
    {
      "name": "Tapas",
      "price": 10,
      "productImage": "uploads\2021-04-04T15-43-36.826Z_tapas.png",
      "_id": "6069dea870f35f0f90242f4a",
      "request": {
        "type": "GET",
        "url": "https://katobackend.azurewebsites.net/api/product/6069dea870f35f0f90242f4a"
      }
    },
    {
      "name": "Cupcake",
      "price": 6,
      "productImage": "uploads\2021-04-04T20-04-27.036Z_detail-5.jpg",
      "_id": "606a1bcba294652bb03e6952",
      "request": {
        "type": "GET",
        "url": "https://katobackend.azurewebsites.net/api/product/606a1bcba294652bb03e6952"
      }
    },
    {
      "name": "Bottle",
      "price": 6,
      "productImage": "uploads/2021-05-23T14-27-33.336Z_Water.jpg",
      "_id": "60aa6655898ea9002454b27f",
      "request": {
        "type": "GET",
        "url": "https://katobackend.azurewebsites.net/api/product/60aa6655898ea9002454b27f"
      }
    },
    {
      "name": "Bottle",
      "price": 6,
      "productImage": "uploads/2021-05-23T14-36-50.590Z_Water.jpg",
      "_id": "60aa688245340b0024735b5c",
      "request": {
        "type": "GET",
        "url": "https://katobackend.azurewebsites.net/api/product/60aa688245340b0024735b5c"
      }
    }
  ]
}

产品响应:

data class ProductResponse (
    @SerializedName("count")
    var count: Int,

    @SerializedName("products")
    var products: List<Product>
)

产品:

data class Product (
    @SerializedName("_id")
    var _id: Int,

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

    @SerializedName("price")
    var price: Number,

    @SerializedName("productImage")
    var productImage: String
)

用户客户端:

interface ApiService {

    @GET(Constants.PRODUCTS_URL)
    fun fetchPosts(@Header("auth-token") token: String): Call<ProductResponse>

}

API 客户:

class ApiClient {
    private lateinit var apiService: ApiService

    fun getApiService(): ApiService {

        // Initialize ApiService if not initialized yet
        if (!::apiService.isInitialized) {
            val retrofit = Retrofit.Builder()
                .baseUrl(Constants.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build()

            apiService = retrofit.create(ApiService::class.java)
        }

        return apiService
    }

}

已验证 Activity:

class Authenticated : AppCompatActivity() {

    private lateinit var sessionManager: SessionManager
    private lateinit var apiClient: ApiClient

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_authenticated)

        lukaku.setOnClickListener(){
            fetchPosts()
        }
    }

    private fun fetchPosts() {

        apiClient = ApiClient()
        sessionManager = SessionManager(this)

        // Pass the token as parameter
        //println("${sessionManager.fetchAuthToken()}")

        apiClient.getApiService().fetchPosts(token = "${sessionManager.fetchAuthToken()}")
            .enqueue(object : Callback<ProductResponse> {
                override fun onFailure(call: Call<ProductResponse>, t: Throwable) {
                    Log.e("", t.message, t)
                }

                override fun onResponse(call: Call<ProductResponse>, response: Response<ProductResponse>) {
                    Log.d("Response", response.toString())
                    println(response)
                    println(response.body())
                }
            })
    }
}

我正在使用 auth-token 作为 header 我可以毫无问题地从我的 Activity 获取令牌,但甚至 link 也无法获取产品API 正在工作

Logcat:

06-01 10:08:05.111 6739-6783/com.mlp.project E/Surface: getSlotFromBufferLocked: unknown buffer: 0x7f4a5805aa00
    com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: Invalid double: "6069dea870f35f0f90242f4a"
        at com.google.gson.internal.bind.TypeAdapters.read(TypeAdapters.java:228)
        at com.google.gson.internal.bind.TypeAdapters.read(TypeAdapters.java:218)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:131)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:131)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
        at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:40)
        at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
        at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
        at retrofit2.OkHttpCall.onResponse(OkHttpCall.java:153)
        at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
        at java.lang.Thread.run(Thread.java:818)
     Caused by: java.lang.NumberFormatException: Invalid double: "6069dea870f35f0f90242f4a"
        at java.lang.StringToReal.invalidReal(StringToReal.java:63)
        at java.lang.StringToReal.initialParse(StringToReal.java:114)
        at java.lang.StringToReal.parseDouble(StringToReal.java:282)
        at java.lang.Double.parseDouble(Double.java:301)
        at com.google.gson.stream.JsonReader.nextInt(JsonReader.java:1201)
        at com.google.gson.internal.bind.TypeAdapters.read(TypeAdapters.java:226)
        at com.google.gson.internal.bind.TypeAdapters.read(TypeAdapters.java:218) 
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:131) 
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222) 
        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) 
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:131) 
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222) 
        at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:40) 
        at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27) 
        at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243) 
        at retrofit2.OkHttpCall.onResponse(OkHttpCall.java:153) 
        at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
        at java.lang.Thread.run(Thread.java:818) 

如错误所述

java.lang.NumberFormatException: Invalid double: "6069dea870f35f0f90242f4a"

var _id: Int更改为var _id: String

您的 _id 键作为字符串值传入,而您在数据模型中将其作为 Int 保存,这会在使用 Gson 进行转换时导致异常,我建议您更新数据模型如下,再试一次。

data class Product (
    @SerializedName("_id")
    var _id: String,

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

    @SerializedName("price")
    var price: Number,

    @SerializedName("productImage")
    var productImage: String
)