Retrofit Method invocation may produce 'java.lang.NullPointerException' - android

Using Retrofit 2.3.0 I am getting the following message in Android Studio
Any suggestions on how I could remove this IDE error message. Thanks

From the Response documentation:
#Nullable
public T body()
The deserialized response body of a successful response.
This means that response.body() can return null, and as a result, invoking response.body().getItems() can throw a NullPointerException. To avoid the warning message, check that response.body() != null before invoking methods on it.
Edit
Discussion on another question revealed that my statements above are not as clear as they need to be. If the original code was:
mAdapter.addItems(response.body().getItems());
It will not be solved by wrapping in a null check like this:
if (response.body() != null) {
mAdapter.addItems(response.body().getItems());
}
The linter (the thing generating the warning) has no way of knowing that each response.body() invocation is going to return the same value, so the second one will still be flagged. Use a local variable to solve this:
MyClass body = response.body();
if (body != null) {
mAdapter.addItems(body.getItems());
}

Related

MutableLiveData NullPointerException Warning

In the MVVM structure, while using the MutableLiveData, even I put an initial value, I got the warning of Unboxing of 'loream.getValue()' may produce 'NullPointerException'. What is correct way of using getValue().
If you look at the source code of LiveData#getValue(), you can see it can return null:
#SuppressWarnings("unchecked")
#Nullable
public T getValue() {
Object data = mData;
if (data != NOT_SET) {
return (T) data;
}
return null;
}
So you always have to account for that fact. You didn't specify if you were using Kotlin or Java (or how you're using getValue() for the matter), so it's hard to tell.
In general, the value(s) of a LiveData stream are often observed and so you wouldn't likely get a null value if you don't "post (or set)" one.
Post a more concrete example if you're looking for specific advice.
If you need a sample, Google has one here.

Compiler complains about wrong type, but it is clearly correct

I have the following issue with Kotlin, here is my code:
val dishesBitmaps: LiveData<List<Bitmap>> = liveData {
val data = getDishesBitmaps()
data?.let {
emit(data)
}
}
getDishesBitmaps() returns List<Bitmap>? however, the compiler shows me the following error
Type inference failed. Expected type mismatch: inferred type is LiveData?> but LiveData> was expected
but data clearly becomes List<Bitmap> after the null check. The strange thing is that it compiles fine if I explicitly cast it like this emit(data as List<Bitmap>) (but again IDE shows that the cast is not needed).
Is this a bug in the compiler or am I doing something wrong?
but data clearly becomes List<Bitmap> after the null check
The compiler could make a smart cast there, but I guess currently it doesn't. Doing the simpler
if (data != null) { emit(data) }
should work. The usual reason to use ?.let instead is if the value checked is a var, which doesn't apply here.
The reason emit(it) works is the type parameter inferred for let.
The strange thing is that it compiles fine if I explicitly cast it like this emit(data as List<Bitmap>) (but again IDE shows that the cast is not needed).
That's not strange by itself, by the cast you are telling the compiler "it doesn't matter what you think type of data is, I know better". It would compile even if you had data: Any?.
The IDE showing the cast is unnecessary is the strange part and something I'd consider a bug (which could well be fixed by making the cast actually unnecessary).
Just place a ? after the LiveData<List<Bitmap>>. Looks like it's nullable. Or you can leave it as it is and change the data? to data!!
Yes as you are adding the null safety on data
data?.let {
emit(data)
}
But your function return type is not null so you need to add ? with the function. So it can be a null value
val dishesBitmaps: LiveData<List<Bitmap>>? = liveData {
val data = getDishesBitmaps()
data?.let {
emit(data)
}
}
data?.let {
emit(data)
}
This block of code translates to
if (date != null) emit(data) else null
If you want return null safety object use elvis
data?.let {
emit(data)
} ?: /**code if data is null**/

Does calling .body() from response Retrofit in try body might returns null?

I have simple snippet code as below:
Sub sub = null;
try {
Response<Sub> response = MyRestApi.getInstance().getSub().execute();
sub = response.body(); // Does variable response is always non null?
} catch (IOException e) {
e.printStackTrace();
}
//
// ... further operations on sub
//
All that I want to know is, can I call safely .body() on responsein try body?
I've tried to preview my method information .getSub() by calling CTRL-Q in Android Studio but I got the only line
Inferred annotations: #org.jetbrains.annotations.NotNull
I believe it should be enough to convince me about that but I had to ask and be 100% sure.
It might be null, even when request is successful, as described on w3c:
"Response data Additional information may follow, in the format of a
MIME message body. The significance of the data depends on the status
code.
The Content-Type used for the data may be any Content-Type which the
client has expressed its ability to accept, or text/plain, or
text/html. That is, one can always assume that the client can handle
text/plain and text/html."
reference: https://www.w3.org/Protocols/HTTP/Response.html
In Retrofit, the body method is defined as Nullable
#Nullable public T body() The deserialized response body of a
successful response.
https://square.github.io/retrofit/2.x/retrofit/retrofit2/Response.html
It might be null, if the response not successful.

RxJava2 Single.Concat for repository pattern

I am using Room with RxJava2 to implement my data layer via Repository Pattern principles.
I have the following simple code which decides where to pick data from.
#Override
public Single<Team> getTeamById(int teamId) {
return Single.
concat(local.getTeamById(teamId),
remote.getTeamById(teamId)).
filter(team -> team != null).
firstOrError();
}
The problem here is that instead of going to the remote source , it returns an error from the first source (local) if the data was not available.
android.arch.persistence.room.EmptyResultSetException: Query returned empty result set: select * from teams where id = ?
How should I instruct the concat to forgo any error that is received and continue its concatenation?
Aslong you're not sure if you can receive at least one Team from you data provider, you should probably think of using Maybe instead of Single.
You can lookup the definition here:
Single as it states:
it always either emits one value or an error notification
Use Maybe instead:
Maybe
there could be 0 or 1 item or an error signalled by some reactive
source
As your error already states there seems to be a problem while extracting results from your query.
Handle your result extraction correctly, so that you check if there are results before trying extracting any. Therefor the Maybe would either return 0 or 1 item, and not throw any error at all when no Team was found.
You cannot pass null in RxJava2. So whenever your local repo is empty you just can't return null in your single. There was a question o stack about handling null objects: Handle null in RxJava2
Also here you can find an article showing you preferred implementation of repository pattern using RxJava2:
https://android.jlelse.eu/rxjava-2-single-concat-sample-for-repository-pattern-1873c456227a
So simplifying - instead of returning null from both local and remote repo pass some sort of "empty" object. That will be useful also in your business logic allowing you to recognize empty set of data.
If you want to continue when the first source errors (instead of completing as empty), you can use onErrorResumeNext instead of concat (I assume both get calls return Observable, adjust as necessary):
return local.getTeamById(teamId)
.onErrorResumeNext(error -> {
if (error instanceof EmptyResultSetException) {
return remote.getTeamById(teamId));
}
return Observable.error(error);
})
.firstOrError();
I used Maybe to solve my Rxjava2 repository pattern problem.
In your case, I would use the following code to sort it out:
//you may need to rewrite your local.getTeamById method
protected Maybe<Team> getTeamById(int teamId) {
Team team = localDataHelper.getTeamById(teamId);
return team != null ? Maybe.just(team) : Maybe.empty();
}
#Override
public Single<Team> getTeamById(int teamId) {
Maybe<Team> cacheObservable = local.getTeamById(teamId);
Maybe<Team> apiCallObservable = remote.getTeamById(teamId).toMaybe();
return Maybe.concat(cacheObservable, apiCallObservable)
.toSingle();
}

kSOAP2 double ID exception

I am attempting to use kSOAP 2 in my android application, and when I try to perform a particular webservice request, I end up getting thrown a "double ID" exception. I was able to find where this gets thrown in the kSOAP source code, it is in the SoapSerializationEnvelope class method public Object read() Here is an excerpt from that code showing the exception being thrown:
if (id != null) {
Object hlp = idMap.get(id);
if (hlp instanceof FwdRef) {
FwdRef f = (FwdRef) hlp;
do {
if (f.obj instanceof KvmSerializable)
((KvmSerializable) f.obj).setProperty(f.index, obj);
else
((Vector) f.obj).setElementAt(obj, f.index);
f = f.next;
} while (f != null);
} else if (hlp != null)
throw new RuntimeException("double ID");
idMap.put(id, obj);
}
I'm not at all sure what this exception is about, or how I can fix it. Anyone know what the deal with this exception is?
Thanks
Edit:
It should be noted that I am also using a SOAP webservice connection method in the iOS version of this application, and the same exact request does not have any problems.
New information:
Upon closer inspection, the problem seems to be resulting from the xml response I am getting containing a <diffgr:before> element, which has tables with the same ID as above. I think this is the cause of the problem, the other requests I have performed up to this point do not have that element in them, and do not have the exception. So to add to the question: can I stop the webservice from sending this block in its response, or get kSOAP to ignore it?
I was able to resolve this by removing the diffgr:before element the webservice was sending. I did that thanks to this post
well, I had the same problem too, but I had no diffgr:before in the xml response (And I can't change the webservice at all). Anyway, the problem was due to some empty values in the response. Using XOM
I managed to remove all empty elements and the it worked like charm. This is done by converting the response to string, loading it into nu.xom.Document element, remove the empty elements from the document and revert it back to InputStream for parsing with ksoap2

Categories

Resources