Home > Software design >  Kotlin why non-null assertion required despite null check
Kotlin why non-null assertion required despite null check

Time:11-01

I'm trying to handle a retrofit response on Kotlin/Android:

if (response.isSuccessful && response.body() != null) {
                    val result = response.body().result

First I don't understand how the response can be successful and the body null. Anyways, if I add the null check I also get "Smart cast to 'xy' is impossible, because 'response.body()' is a complex expression" Add non-null asserted code (!!) Actually to me those are two separate warnings, but why the null-Assertion request?

CodePudding user response:

The compiler can’t know that body() is guaranteed to return the same thing each time so it can’t smart-cast it to non-null. Also, it doesn’t know anything as complex as the fact that the body won’t be null if isSuccessful is true.

Since we know from the documentation of this library that it will always be the same, it’s safe to use !!. But you could alternatively copy the value to a local variable and work with that variable in your null check. Then you could be sure your code is safe even if you misinterpreted the documentation.

I don't really use Retrofit myself, but from a little bit of reading about it, I know that you can work with it more naturally in Kotlin by using suspend functions, and then you wouldn't have to work with callbacks and Response objects. So instead of creating a function that returns a Call<MyData>, followed by enqueuing the call, listening for success/failure, and then unwrapping the body if it's successful; instead you can mark the function as suspend and return MyData directly. Use try/catch or runCatching when making the function call, because it throws when not successful.

CodePudding user response:

You need to set response.body() to a variable and then check for its nulability:

val body = response.body()
if (response.isSuccessful && body != null) {
    val result = body.result
}
  • Related