【问题标题】:Retrofit response body gives null改造响应体给出 null
【发布时间】:2020-09-12 14:52:24
【问题描述】:

我正在尝试使用返回 JSON 的 API,并且我正在使用 Retrofit 来获取响应并对其进行解析

API 重新运行 JSON,如下所示:

{
 "total": 1244881,
 "totalHits": 500,
 "hits": [
  {
   "id": 5205518,
   "pageURL": "https://pixabay.com/photos/landscape-sea-sky-clouds-sunset-5205518/",
   "type": "photo",
   "tags": "landscape, sea, sky",
   "previewURL": "https://cdn.pixabay.com/photo/2020/05/22/14/04/landscape-5205518_150.jpg",
   "webformatWidth": 640,
   "webformatHeight": 427,
    ...
    ...
  },
    ...
    ...
  ]
}

为了让 GSON 将此 json 转换为对象,我创建了两个类: 第一个是:RquestModel.java

public class RequestModel {

    @SerializedName("total")
    private long total;

    @SerializedName("totalHits")
    private long totalHits;

    @SerializedName("hits")
    private List<Image> hits;

    //Getters and setters down here...

}

json 中数组的第二个类是:

public class Image {

    @SerializedName("id")
    private long id;

    @SerializedName("pageURL")
    private String pageURL;

    @SerializedName("type")
    private String type;

    @SerializedName("tags")
    private String tags;

    @SerializedName("previewURL")
    private String previewURL;

    @SerializedName("previewWidth")
    private long previewWidth;

    @SerializedName("previewHeight")
    private long previewHeight;

    @SerializedName("webformatURL")
    private String webformatURL;

    @SerializedName("webformatWidth")
    private long webformatWidth;

    @SerializedName("webformatHeight")
    private long webformatHeight;

    @SerializedName("largeImageURL")
    private String largeImageURL;

    @SerializedName("imageWidth")
    private long imageWidth;

    @SerializedName("imageHeight")
    private long imageHeight;

    @SerializedName("imageSize")
    private long imageSize;

    @SerializedName("views")
    private long views;

    @SerializedName("downloads")
    private long downloads;

    @SerializedName("favorites")
    private long favorites;

    @SerializedName("likes")
    private long likes;

    @SerializedName("comments")
    private long comments;

    @SerializedName("user_id")
    private long userId;

    @SerializedName("user")
    private String user;

    @SerializedName("userImageURL")
    private String userImageURL;


    //Getters and Setters down here ..... 



}

而对于GSON转换器使用的接口是这样的:

public interface ImageAPIService {

    @GET(".")
    public Call<RequestModel> getRequest();

}

当我尝试像这样使用回调的响应时:

Retrofit retrofit = new Retrofit.Builder()
                            .baseUrl(API_URL)
                            .addConverterFactory(GsonConverterFactory.create())
                            .build();

ImageAPIService api = retrofit.create(ImageAPIService.class);

Call<RequestModel> request = api.getRequest();

request.enqueue(new Callback<RequestModel>() {
    @Override
    public void onResponse(Call<RequestModel> call, Response<RequestModel> response) {
        mViewModel.setTxt(response.body().getTotal() + "");
    }

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

    }
});

给出一个异常类型:java.lang.NullPointerException

java.lang.NullPointerException: Attempt to invoke virtual method 'long com.mapps.pixabayclient.models.RequestModel.getTotal()' on a null object reference

我尝试调试它,对我来说一切都很好,我不知道我错过了什么。如果有人能注意到这个错误,我将非常感激。

提前感谢您的帮助。

【问题讨论】:

  • 首先检查response.isSuccessful() 并记录结果以查看问题所在。同时记录 http 响应代码以了解发生了什么
  • inside on response set RequestModel req = response.body(); 然后尝试获取req.getTotal()
  • @sonnet,很奇怪,它给出了 400 错误代码,我不知道为什么我更新了帖子并将 GSON 转换器用来查看该级别错误的接口。
  • 这可能是有问题的@GET(".")。可以发一下你的网址吗?不必精确。例如:https://example.com/api/hits 什么的
  • @sonnet,好吧,我去。

标签: java android json gson retrofit2


【解决方案1】:

因此,您已经发现的问题是,在您的设置中,密钥已从请求中删除。这是我使用您的设置提出请求时的响应。

响应{protocol=http/1.1, code=400, message=Bad Request, url=https://pixabay.com/api/}

但事实并非如此。根据 Jake Wharton 的this,如果我们使用@GET("."),那么整个 base_url 就变成了请求 url。出于某种原因,您的情况并非如此。 [也许如果我们使用一些拦截器记录请求 url,那么我们可以更好地了解正在发生的事情(无论是改造问题还是后端问题)]。

无论如何,一种解决方案是为每个请求传递 api 密钥,如下所示:

@GET(".")
public Call<RequestModel> getRequest(@Query("key") String key);

然后像这样调用函数:

api.getRequest("my_api_key")

另一种解决方案是将 api 密钥硬编码为 @GET("api/?key=xxxxx"),就像您已经做的那样。

更好的解决方案是use okhttp interceptor拦截请求,并在url中添加api key查询参数。使用此解决方案,您不必为每个函数调用传递 api 密钥。

【讨论】:

  • 感谢 mate 的帮助,我第一次编写的代码由于某种原因无法正常工作,这真的很奇怪,我会研究它并在这篇文章中为我详细调试。无论如何,谢谢,你帮了很多忙!。
【解决方案2】:

问题出在@GET 注释中,因为我将 api/?key 移到了 GET 注释的括号内 -> @GET("api/?key=xxxxxxx") 但现在的问题是我应该在每个 GET 或任何其他请求类型中传递密钥。

是否有一种解决方法可以系统地在每个请求中传递密钥?

【讨论】:

  • 感谢您发现问题。我也在调试这个问题,正在准备更详细的答案
猜你喜欢
  • 1970-01-01
  • 2018-09-10
  • 2018-11-04
  • 2016-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-15
  • 2017-01-15
相关资源
最近更新 更多