Retrofit2:如何正确检查 response.body() 的有效性? [英] Retrofit2: How to properly check the validity of response.body()?

查看:85
本文介绍了Retrofit2:如何正确检查 response.body() 的有效性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

自版本 retrofit2.retrofit:2.3.0 起,即使在检查正文时,我也会在 response.body() 上收到 NullPointerException 警告对于 null 之前:

方法调用getCar()"可能会产生java.lang.NullPointerException"

2.3.0 的变更日志中有一个与空检查相关的条目:

<块引用>

Retrofit 现在使用 @Nullable 来注释所有可能为空的值.[...] 我们使用 @ParametersAreNonnullByDefault 并且所有参数和返回类型永远不会为空,除非明确注释 @Nullable.

这是预期的行为吗?在我看来 response.body() 应该是不可变的,所以我检查图片 1 不应显示警告.

这不是关于 NullPointerExceptions 的问题——而是关于如何正确处理 Retrofit2 响应的方式.为了暂时没有警告,我必须做这样的事情:

if(response != null) {CarResponseBody body = response.body();if (body != null && body.getCar() != null){CarResponse car = body.getCar();}}

很多代码只是为了检查是否有有效的响应...

解决方案

这是预期的行为吗?

如果你检查Response的JavaDoc你可以阅读

<块引用>

@Nullable public T body()成功响应的反序列化响应主体.
Javadoc:响应

正如它所暗示的,如果响应成功,body() 不会是 null.要检查是否成功,您有 isSuccessful() which

<块引用>

如果 code() 在 [200..300] 范围内,则返回 true.

所以 @Nullable 是一个有效的选择,因为在任何不成功的情况下,响应可以是 null,例如无网络、无效请求或其他错误.

IDE 中的提示是一个 lint 警告,用于检查您的源代码中是否存在常见错误或错误的可能来源.

这就是为什么 body() 可能是 null 以及为什么 lint 首先将此报告为警告的原因.

<块引用>

在我看来 response.body() 应该是不可变的,所以我在图 1 中的检查不应该显示警告.

理论上你是对的.你我都知道 body() 不是可变的,但这里的问题是 this lint check 无法知道.

T res1 = response.body();//可能为空T res2 = response.body();//...也许还是null?

Lint 是一种静态源代码和字节码分析器,有助于防止常见错误和错误,其中一项 lint 检查试图防止 NPE.如果你注释一个方法 @Nullable,所有的检查都知道返回的值 可能null,如果你试图直接对调用结果进行操作.

//响应是否两次返回相同的值?谁知道?response.body() != null &&response.body().getCar() != null

处理响应的方式实际上是摆脱 lint 警告的唯一方法——除了抑制或禁用它.

通过将其分配给局部变量,您可以确保某个值在某个时候不是 null 并且将来不会变为 null,并且 lint 也能看到这一点.

CarResponseBody body = response.body();//将 body() 赋值给一个局部变量if (body != null && body.getCar() != null) {//变量不为空CarResponse car = body.getCar();//安全访问 body,car 也不为空//一切安好!}

<小时><块引用>

这是预期的行为吗?

是的.@Nullable 是提示方法可能返回 null 的好方法,如果您在上返回 null,您也应该在自己的代码中使用它一些路径 因为 lint 可以警告可能的 NullPointerExceptions.

如果一个方法可能返回 null,您必须将其分配给一个本地字段并检查该字段的 null 值,否则您可能会冒该值可能已更改的风险.

Car car = response.getBody();//car 可能为空如果(汽车!= null){//car 永远不会为空}

不同的选择/方法

我看到您似乎还额外将您的响应对象包装在一个附加层中.

CarResponseBody body = response.body();汽车车 = body.getCar()

如果您想从代码中移除复杂性,您应该在较早的阶段查看如何移除此包装 *ResponseBody.您可以通过注册您自己的转换器并在那里添加其他处理来实现.您可以在此Jake Wharton 的改造演讲

上了解更多相关信息

另一种完全不同的方法是将 RxJava 与 Retrofit 结合使用,这样就无需自己检查响应.您将获得成功或错误,您可以通过 Rx 方式处理.

Since version retrofit2.retrofit:2.3.0 I'm getting NullPointerException warnings on response.body() even when checking the body for null before:

Method invocation 'getCar()' may produce 'java.lang.NullPointerException'

In the changelog for 2.3.0 was an entry related to null checks:

Retrofit now uses @Nullable to annotate all possibly-null values. [...] We use @ParametersAreNonnullByDefault and all parameters and return types are never null unless explicitly annotated @Nullable.

It that the intended behavior? In my point of view response.body() should be immutable, so my check in Picture 1 should not show a warning.

This is not a question about NullPointerExceptions - it's about the way how to handle responses of Retrofit2 properly. To not have warnings at the moment I have to do something like this:

if(response != null) {
    CarResponseBody body = response.body();
    if (body != null && body.getCar() != null){
        CarResponse car = body.getCar();
    }
}

A lot of code to just check if there is a valid response...

解决方案

Is that the intended behavior?

If you check the JavaDoc of Response<T> you can read

@Nullable public T body() The deserialized response body of a successful response.
Javadoc: Response

As it suggests, body() won't be null if the response was successful. To check for success you have isSuccessful() which

Returns true if code() is in the range [200..300).

So the @Nullable is a valid choice, since the response can be null in any non-success case, e.g. no network, an invalid request, or some other error.

The hint in your IDE is a lint warning that checks your source code for possible sources of common errors or bugs.

This is why body() might be null and why lint reports this as a warning in the first place.

In my point of view response.body() should be immutable, so my check in Picture 1 should not show a warning.

And in theory you're correct. You and I both know that body() is not mutable, but the problem here is that this lint check has no way of knowing.

T res1 = response.body(); // could be null
T res2 = response.body(); // ...maybe still null?

Lint is a static source and byte code analyzer that helps to prevent common bugs and errors and one of those lint checks tries to prevent NPEs. If you annotate a method @Nullable all the check knows is that the returned value could be null and it will raise a warning if you try to operate on the result of the call directly.

// does response return the same value twice? who knows?
response.body() != null && response.body().getCar() != null

The way you handle your response is actually the only way to get rid of the lint warning—other than suppressing or disabling it.

By assigning it to a local variable you are able to ensure that a value is not null at some point and that it won't become null in the future, and lint is also able to see that.

CarResponseBody body = response.body(); // assign body() to a local variable
if (body != null && body.getCar() != null) { // variable is not null
    CarResponse car = body.getCar(); // safe to access body, car is also not null
    // everything is fine!
}


It that the intended behavior?

Yes. @Nullable is a good way to hint that a method might return null and you should also use it in your own code if you return null on some paths because lint can warn of possible NullPointerExceptions.

If a method might return null you will have to assign it to a local field and check the field for null values, or you risk that the value could have changed.

Car car = response.getBody(); // car could be null
if(car != null) {
  // car will never be null
}

Different options / approaches

I see that you also additionally seem to wrap your response object in an additional layer.

CarResponseBody body = response.body();
Car car = body.getCar()

If you want to remove complexity from your code, you should have a look at how to remove this wrapping *ResponseBody at an earlier stage. You can do so by registering your own Converter and adding additional handling there. You can see more about this on this Retrofit talk by Jake Wharton

Another completely different approach would be to use RxJava with Retrofit which removes the need to check the response yourself. You'll either get a success or an error, which you can handle the Rx way.

这篇关于Retrofit2:如何正确检查 response.body() 的有效性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆