-1

I'm creating an app that takes a list of apps installed on the device and checks for version updates from the google play store.

This is my method to get the app information based on package name:

    public Observable<DetailsResponse> getUpdates(@NonNull List<ApplicationInfo> apps) {
        return Observable.fromIterable(apps)
            .flatMap(appInfo -> googlePlayApiService.getDetails(appInfo.packageName));
    }

It works fine if the package is actually on the google play store, but it returns retrofit2.adapter.rxjava2.HttpException: HTTP 404 if the package name is not found (ie: sideloaded app)

This is my method to handle the observables:

 updatesViewController.getUpdates(apps)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .as(AutoDispose.autoDisposable(ViewScopeProvider.from(this)))
            .subscribe(responseItem -> responseList.add(responseItem),
                    throwable -> responseList.add(null), //404's here, doesn't do the onComplete at all.
                    () -> { // onComplete
                        for (int i = 0; i < apps.size(); ++i) {
                          if (responseList.get(i) != null && apps.get(i).isLowerVersion(responseList.get(i)) {
                              doSomething();
                          }
                     });

If all the apps are on the playstore, this works as intended. I want to make it so that if one or more of the apps are not found in the playstore, it can still doSomething() on the apps that are found, while ignoring the apps that aren't. Any help is appreciated!

Brandon Xia
  • 407
  • 3
  • 19

3 Answers3

1

You add null (responseList.add(null)) to the list of responses when you hit one of those 404s (apps not registered on playstore).

Then as logically you are checking and doing something if the version of the app is lower so you can doSomething(). But the check also checks nulls (if (responseList.get(i) != null[...]), therefore you have nulls in the list and those will not doSomething.

Is doSomething dependant on some data in the item? If not, you could do something like:

if(responseList.get(i) == null || (responseList.get(i) != null && apps.get(i).isLowerVersion(responseList.get(i)))

This will call doSomething for all the apps that is lowerVersion OR the missing ones (e.g: ones resulted in 404s) Remember the assumption above, that the doSomething() doesn't need actual data from this retrieval - otherwise subsequent actions in the doSomething() will fail.

MadaManu
  • 868
  • 4
  • 10
  • doSomething is dependant on the information, (I should have written `doSomething(apps.get(i));`. My problem is that when the program hits onError once, the whole things stops and never gets to onComplete. Is there a way to just ignore the null ones/404 errors and only doSomething() on the apps that were found? – Brandon Xia Jan 07 '20 at 01:04
  • Oh I see, try and use doOnError instead of handling throwable. `doOnError(throwable -> responseList.add(null))`. – MadaManu Jan 07 '20 at 01:11
  • I think this does the same as having the `onError` lambda parameter in my subscribe method, if it hits an error it also just ends the whole observable and doesn't get to the onComplete – Brandon Xia Jan 07 '20 at 17:34
1

My solution to this problem:

I added a .onErrorResumeNext(Observable.empty()); which effectively skips the items that cause errors.

public Observable<DetailsResponse> getUpdates(@NonNull List<ApplicationInfo> apps) {
     return Observable.fromIterable(apps)
        .flatMap(appInfo -> googlePlayApiService.getDetails(appInfo.packageName)
        .onErrorResumeNext(Observable.empty()));
}

Then in onComplete, instead of looping through all my apps, I only loop through the ones that are in the responseList, which was mostly just a logic error, not an rxJava error.

Brandon Xia
  • 407
  • 3
  • 19
0

You can use onErrorResumeNext(..)

public Observable<DetailsResponse> getUpdates(@NonNull List<ApplicationInfo> apps) {
    return Observable.fromIterable(apps)
        .flatMap(appInfo -> googlePlayApiService.getDetails(appInfo.packageName).OnErrorResumeNext(getFallbackStream()));
}

However, you have to keep in mind that HTTP 404 is not an error, as a successful HTTP call was made unless your HTTP connector maps a 404 to a throwable at some lower level. If not, then you'll have to do something like:

if(404 == appInfo.getResponseCode()) {
   return getFallbackStream();
}

inside the flatMap.

Prashant Pandey
  • 4,332
  • 3
  • 26
  • 44