使用 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
)
我无法从我的 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
)