如何在 Kotlin 中调用这个 API?

发布于 2025-01-11 22:41:28 字数 2076 浏览 0 评论 0原文

我正在尝试调用这个API: https://dog-facts-api.herokuapp。 com/api/v1/resources/dogs?number=2

如您所见,它返回一个 Json,其中包含有关狗的随机事实, 我的问题是当我将我的baseUrl与retrofit一起放置时:

private fun getRetrofit(): Retrofit{
        return Retrofit.Builder()
            .baseUrl("https://dog-facts-api.herokuapp.com/api/v1/resources/dogs?number=")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

如果我像这样放置url,它就不起作用,因为它说必须以“/”结尾 但如果我添加它,它就不起作用了。

另外,我尝试这样写:

.baseUrl("https://dog-facts-api.herokuapp.com/api/v1/resources/")

并像这样进行调用:

val call = getRetrofit().create(APIService::class.java).getFactsByNumber("dogs?number=$number")

但同样,它不起作用,它会抛出错误:

E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1 进程:com.eltonga.dogfacts,PID:11927 com.google.gson.JsonSyntaxException:java.lang.IllegalStateException:预期为 BEGIN_OBJECT,但在第 1 行第 2 列路径处为 BEGIN_ARRAY $

我的接口:

interface APIService {
    @GET
    suspend fun getFactsByNumber(@Url url: String): Response<FactsResponse>
}

我的数据类:

data class FactsResponse(var fact: List<String>)

我调用 API 的函数:

private fun searchByNumber(number:Int){
        CoroutineScope(Dispatchers.IO).launch {
            val call = getRetrofit().create(APIService::class.java).getFactsByNumber("dogs?number=$number")
            val the_facts = call.body()

            runOnUiThread {
                if(call.isSuccessful){
                    val factsData = the_facts?.fact ?: emptyList()
                    facts.clear()
                    facts.addAll(factsData)
                    adapter.notifyDataSetChanged()
                }else{
                    Toast.makeText(binding.btnGo.context, "Error", Toast.LENGTH_SHORT).show()
                }
            }

        }
    }

我能做什么?我对 API 工作还很陌生

I'm trying to call this API:
https://dog-facts-api.herokuapp.com/api/v1/resources/dogs?number=2

As you can see, it returns a Json with random facts about dogs,
my problem is when I put my baseUrl with retrofit:

private fun getRetrofit(): Retrofit{
        return Retrofit.Builder()
            .baseUrl("https://dog-facts-api.herokuapp.com/api/v1/resources/dogs?number=")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

If I put the url like that, it doesn't work, because it says that must end with an "/"
But if I add it, it doesn't work.

Also, I tried to put just like:

.baseUrl("https://dog-facts-api.herokuapp.com/api/v1/resources/")

And making the call like this:

val call = getRetrofit().create(APIService::class.java).getFactsByNumber("dogs?number=$number")

But again, it didn't work, it throws an error:

E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.eltonga.dogfacts, PID: 11927
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $

My Interface:

interface APIService {
    @GET
    suspend fun getFactsByNumber(@Url url: String): Response<FactsResponse>
}

My data class:

data class FactsResponse(var fact: List<String>)

The function where I call the API:

private fun searchByNumber(number:Int){
        CoroutineScope(Dispatchers.IO).launch {
            val call = getRetrofit().create(APIService::class.java).getFactsByNumber("dogs?number=$number")
            val the_facts = call.body()

            runOnUiThread {
                if(call.isSuccessful){
                    val factsData = the_facts?.fact ?: emptyList()
                    facts.clear()
                    facts.addAll(factsData)
                    adapter.notifyDataSetChanged()
                }else{
                    Toast.makeText(binding.btnGo.context, "Error", Toast.LENGTH_SHORT).show()
                }
            }

        }
    }

What can I do? I'm pretty new working with API

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

云裳 2025-01-18 22:41:28

预期为 BEGIN_OBJECT,但结果为 BEGIN_ARRAY

上述错误表明 API 响应的根部有一个数组/列表,并且您正尝试将响应反序列化为以下对象:不是数组/列表。

interface APIService {
    @GET
    suspend fun getFactsByNumber(@Url url: String): Response<FactsResponse>
}

data class FactsResponse(var fact: List<String>)

如果响应采用以下格式,这将起作用

{
  "fact": [
    "Greyhounds can reach a speed of up to 45 miles per hour.",
    "The average dog can run about 19 mph. Greyhounds are the fastest dogs on Earth and can run at speeds of 45 mph."
  ]
}

但是由于响应采用以下格式,

[
  {
    "fact": "Greyhounds can reach a speed of up to 45 miles per hour."
  },
  {
    "fact": "The average dog can run about 19 mph. Greyhounds are the fastest dogs on Earth and can run at speeds of 45 mph."
  }
]

您需要将返回类型用 List 包装,并且该类应该只有一个 fact< /code> 字符串字段。因此函数和数据类应该定义为

interface APIService {
    @GET
    suspend fun getFactsByNumber(@Url url: String): Response<List<FactsResponse>>
}

data class FactsResponse(val fact: String)

另外,定义接口函数以避免每次传递它 "dogs?number=$number" 的更好方法是

interface APIService {
    @GET("dogs")
    suspend fun getFactsByNumber(@Query("number") number: String): Response<List<FactsResponse>>
}

并将函数调用为

val apiService = getRetrofit().create(APIService::class.java)

val call = apiService.getFactsByNumber(number) // where number is already defined and initialized with a value

Expected BEGIN_OBJECT but was BEGIN_ARRAY

The above error indicates that the API response has an array/list at the root and you are trying to deserialize the response to an object that is not an array/list.

interface APIService {
    @GET
    suspend fun getFactsByNumber(@Url url: String): Response<FactsResponse>
}

data class FactsResponse(var fact: List<String>)

This would work if the response is in the below format

{
  "fact": [
    "Greyhounds can reach a speed of up to 45 miles per hour.",
    "The average dog can run about 19 mph. Greyhounds are the fastest dogs on Earth and can run at speeds of 45 mph."
  ]
}

But since the response is in the below format

[
  {
    "fact": "Greyhounds can reach a speed of up to 45 miles per hour."
  },
  {
    "fact": "The average dog can run about 19 mph. Greyhounds are the fastest dogs on Earth and can run at speeds of 45 mph."
  }
]

You need to have the return type wrapped with a List and the class should have only a fact String field. So the function and data class should be defined as

interface APIService {
    @GET
    suspend fun getFactsByNumber(@Url url: String): Response<List<FactsResponse>>
}

data class FactsResponse(val fact: String)

Also, a better way of defining the interface function to avoid passing it "dogs?number=$number" everytime is

interface APIService {
    @GET("dogs")
    suspend fun getFactsByNumber(@Query("number") number: String): Response<List<FactsResponse>>
}

And calling the function as

val apiService = getRetrofit().create(APIService::class.java)

val call = apiService.getFactsByNumber(number) // where number is already defined and initialized with a value
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文