自retrofit2.retrofit:2.3.0
版以来,即使在NullPointerException
之前检查正文时,我response.body()
也会收到null
警告:
Method invocation 'getCar()' may produce '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();
}
}
很多代码只是检查是否有有效的响应......
答案 0 :(得分:16)
这是预期的行为吗?
如果您检查Response<T>
的JavaDoc,您可以阅读
@Nullable public T body() 成功响应的反序列化响应主体 Javadoc: Response
根据建议,如果回复成功,body()
将不会是null
。要检查是否成功,您需要isSuccessful()
如果code()在[200..300)范围内,则返回true。
因此,@Nullable
是一个有效的选择,因为在任何不成功的情况下,响应可以是null
,例如没有网络,无效请求或其他错误。
IDE中的提示是一个lint警告,它会检查源代码是否存在常见错误或错误的可能来源。
这是为什么 body()
可能是null
以及为什么lint首先将此报告为警告。
在我的观点中,response.body()应该是不可变的,所以我在图1中的检查不应该显示警告。
理论上你是对的。你和我都知道body()
不可变,但问题是这个 lint 检查无法知道。
T res1 = response.body(); // could be null
T res2 = response.body(); // ...maybe still null?
Lint是一个静态源和字节码分析器,有助于防止常见的错误和错误,其中一个lint检查试图阻止NPE。如果您注释方法@Nullable
,则所有检查都知道返回的值可能为null
,如果您尝试操作调用结果,它将发出警告直接
// does response return the same value twice? who knows?
response.body() != null && response.body().getCar() != null
处理响应的方式实际上是摆脱lint警告的唯一方法 - 除了抑制或禁用它。
通过将其分配给局部变量,您可以确保某个值在某个时刻不是null
并且将来不会变为null
,并且lint也能够看到了。
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!
}
是预期的行为?
是。 @Nullable
是提示方法可能返回null
的好方法,如果您在某些路径上返回null
,也应该在自己的代码中使用它,因为 lint可以警告可能的NullPointerExceptions。
如果方法可能会返回null
,则必须将其分配给本地字段并检查字段中的null
值,否则您可能会更改该值。
Car car = response.getBody(); // car could be null
if(car != null) {
// car will never be null
}
我看到你还似乎还将你的响应对象包装在一个附加层中。
CarResponseBody body = response.body();
Car car = body.getCar()
如果要从代码中删除复杂性,应该先了解如何在早期阶段删除此包装*ResponseBody
。您可以通过注册自己的转换器并在那里添加其他处理来实现。您可以在此Retrofit talk by Jake Wharton
另一种完全不同的方法是将RxJava与Retrofit一起使用,这样就无需自行检查响应。您将获得成功或错误,您可以处理Rx方式。
答案 1 :(得分:1)
我通常在WhateverResponse类中创建一个isValid()或hasResults()方法
boolean isValid(){
return getCar() != null && getWheel() != null && somethingElse
}
使用
if(response.isValid()){
//do your other if's
}
不需要检查空响应。 errorBody()将不为null或在此之前将调用retrofit2.Callback onFailure()方法
答案 2 :(得分:0)
试试这个
export function updateSettings(id, item) {
return dispatch => {
dispatch({ type: 'SETTINGS_IS_LOADING' })
console.log(dispatch)
console.log('FÖRE', item)
axios
.put(`${settings.hostname}/locks/${id}`, item)
.then(() => {
console.log(item)
dispatch({
type: 'SETTINGS_UPDATED',
payload: {
item,
id
}
})
console.log('EFTER', item) // It's still the same
})
.catch(err => console.log(err))
}
}