在Android中,Retrofit响应返回null。

15

我想显示一个来自JSON值的文本。我正在使用Retrofit进行API调用,但不确定我是否做得正确。无论如何,这是我的代码。

这是网址链接:http://api.icndb.com/jokes/random

该网站每次都会显示一个随机笑话。以下是该网站输出的示例:

{ "type": "success", "value": { "id": 175, "joke": "When Chuck Norris was a baby, he didn't suck his mother's breast. His mother served him whiskey, straight out of the bottle.", "categories": [] } } 

fragment.java

    String url = "http://api.icndb.com/";

    Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(url)
            .addConverterFactory(GsonConverterFactory.create());

    Retrofit retrofit = builder.build();

    RetroFitHelper client = retrofit.create(RetroFitHelper.class);
    Call<Api> call = client.findJoke("random");

    call.enqueue(new Callback<Api>() {
        @Override
        public void onResponse(Response<Api> response, Retrofit retrofit) {

            String result = response.body().getJoke();

            Toast.makeText(getContext()," The word is: " + result ,Toast.LENGTH_LONG).show();
        }

        @Override
        public void onFailure(Throwable t) {
            Toast.makeText(getContext()," Error..." ,Toast.LENGTH_LONG).show();

        }
    });

RetroFitHelper.java

public interface RetroFitHelper {

    @GET("/jokes/{random}")
    Call<Api> findJoke(@Path("random") String random);

}

模型类


public class Api {

    @SerializedName("joke")
    private String joke;

    public String getJoke() {
        return joke;
    }

    public void setJoke(String joke){
        this.joke = joke;
    }
}

请确保在清单文件中添加了INTERNET权限。 - Aswin P Ashok
谢谢,但它已经启用了。 - makkhay gurung
2
看起来你的模型类不太对。看看Navaneet的答案。 - Aswin P Ashok
5个回答

19
给定的 JSON 响应中有一个名为 value 的 JSON 对象,它位于另一个 JSON 对象内(形式为 {..,"value":{}})。因此我们需要两个模型类 - 一个用于外部 JSON 对象,另一个用于内部 JSON 对象(value)。
你需要创建两个如下的模型类:
public class Api {

@SerializedName("type")
@Expose
private String type;
@SerializedName("value")
@Expose
private Value value;

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public Value getValue() {
return value;
}

public void setValue(Value value) {
this.value = value;
}

并且下一个是关于值对象的

public class Value {

@SerializedName("id")
@Expose
private Integer id;
@SerializedName("joke")
@Expose
private String joke;
@SerializedName("categories")
@Expose
private List<Object> categories = null;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getJoke() {
return joke;
}

public void setJoke(String joke) {
this.joke = joke;
}

public List<Object> getCategories() {
return categories;
}

public void setCategories(List<Object> categories) {
this.categories = categories;
}

}
现在,response.body()将拥有外层 JSON 对象(Api)的结果,response.body().getValue()将拥有内层 JSON 对象(Value)的结果。
现在,在您的响应回调函数中,获取响应如下:
String result = response.body().getValue().getJoke();

请确保在您的清单文件中声明了必要的互联网权限,就像这样:

<uses-permission android:name="android.permission.INTERNET" />

请确保您在应用级别的build.gradle文件中设置了最新的依赖项

implementation 'com.squareup.retrofit2:retrofit:2.4.0'

implementation 'com.squareup.retrofit2:converter-gson:2.4.0'


非常好用,谢谢。我有一个快速问题,如何在发送GET请求后输出完整的URL?换句话说,如果onResponse出现错误,我只想输出完整的URL。再次感谢。 - makkhay gurung
什么错误?假设您的响应不成功,则在onResponse回调中的if(!response.isSuccess()){}内添加您的消息(或要输出的URL)作为烤面包片。 - Navneet Krishna

5
正如@Aswin所建议和@Navneet所回答的,您的POJO类存在问题。我建议您使用jsonschema2pojoRoboPOJOGenerator,这样下次就可以避免遇到此类错误。
步骤:
1)前往http://www.jsonschema2pojo.org/ 2)将您的响应粘贴到该网站上并输入包名和类名
3)选择目标语言为Java或Kotlin(如果您在使用)
4)源类型为Json
5)注解样式为Gson
6)点击预览
7)将这些类复制并粘贴到您的应用程序包中

那个网站真的很有帮助,非常感谢。 - makkhay gurung

2
你所使用的模型类存在问题。
API的响应如下:
{
"type": "success",
"value": {
    "id": 429,
    "joke": "Chuck Norris has never been accused of murder because his roundhouse kicks are recognized as &quot;acts of God.&quot;",
    "categories": []
}
}

因此,要将响应中的笑话值作为字符串获取,您的模型类应如下所示:

public class Api implements Serializable {

@SerializedName("type")
@Expose
private String type;
@SerializedName("value")
@Expose
private Value value;

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

public Value getValue() {
    return value;
}

public void setValue(Value value) {
    this.value = value;
}
}

你的值类是:

public class Value implements Serializable
{
@SerializedName("id")
@Expose
private Integer id;
@SerializedName("joke")
@Expose
private String joke;
@SerializedName("categories")
@Expose
private List<Object> categories = null;

public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public String getJoke() {
    return joke;
}

public void setJoke(String joke) {
    this.joke = joke;
}

public List<Object> getCategories() {
    return categories;
}

public void setCategories(List<Object> categories) {
    this.categories = categories;
}
}

现在你可以像这样获取你的值:

 call1.enqueue(new Callback<Api>() {
        @Override
        public void onResponse(Call<Api> call, Response<Api> response) {

            if (response.isSuccessful()) {
                String jokeValue = response.body().getValue().getJoke();
            }
        }

        @Override
        public void onFailure(Call<Api> call, Throwable t) {

            t.printStackTrace();
        }
    });

根据您的需求进行更改。

愉快编码...


1
将以下权限添加到你的 AndroidManifest.xml 文件中。
<uses-permission android:name="android.permission.INTERNET" />

在你的 build.gradle (Module:app) 中添加以下内容。
compile 'com.squareup.okhttp3:okhttp:3.9.0'
compile 'com.google.code.gson:gson:2.8.2'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'

添加这个接口,
public interface ApiInterface {
public static final String BASE_URL = "http://api.icndb.com";

@GET("/jokes/{random}")
Call<Api> GetApiResponse(@Path("random") String random);


public class ApiClient {
    public static ApiInterface apiInterface;

    public static ApiInterface getApiInterface() {
        if (apiInterface == null) {
            Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
            apiInterface = retrofit.create(ApiInterface.class);
            return apiInterface;
        } else {
            return apiInterface;
        }
    }

}


}

创建两个模型类: com.example.app.Api.java
package com.example.app;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Api {

@SerializedName("type")
@Expose
 private String type;
@SerializedName("value")
 @Expose
 private Value value;

 public String getType() {
 return type;
 }

public Value getValue() {
return value;
}

}

创建值模型类:com.example.app.Value.java
package com.example.app;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Value {

@SerializedName("id")
@Expose
private Integer id;
@SerializedName("joke")
@Expose
private String joke;

public int getId() {
return id;
}

public String getJoke() {
return joke;
}

}

在您的Activity的onCreate()方法中添加以下代码:
  ApiInterface.ApiClient.getApiInterface().GetApiResponse('random').enqueue(new Callback<Api>() {
                @Override
                public void onResponse(Call<Api> call, Response<Api> response) {
                  String Joke=response.body.getValue().getJoke();
                    Toast.makeText(MainActivity.this, Joke, Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onFailure(Call<Api> call, Throwable t) {

                }
            });

0

不确定这是否是一个好的方法,但对我有效

    val json = JSONObject(Gson().toJson(response.body().data)).toString()
Gson().fromJson(json, User::class.java)

我的响应结构是:

{
  "success":true,
  "data":{
     "p1":32,
     "p2":34
      },
  "message":""
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接