How to properly handle onError inside RxJava (Android)?

后端 未结 3 1413
南笙
南笙 2021-01-01 09:56

I\'m getting a list of installed apps on the device. It\'s a costly operation, so I\'m using Rx for that:

    Observable observable = Observable         


        
相关标签:
3条回答
  • 2021-01-01 10:02

    .doOnError() is an operator, and is not as such a part of the Subscriber.

    Therefore, having a .doOnError() does not count as an implemented onError().

    About the question in one of the comments, of course it is possible to use lambdas.

    In this case simply replace

    .doOnError(throwable -> L.e(TAG, "Throwable " + throwable.getMessage()))
    .subscribe(s -> createListView(s, view))
    

    with

    .subscribe(s -> createListView(s, view),
        throwable -> L.e(TAG, "Throwable " + throwable.getMessage()))
    
    0 讨论(0)
  • 2021-01-01 10:04

    My take is: you are probably using Action1 in

    .subscribe(s -> createListView(s, view));
    

    You will need to replace it with Subscriber or Observer which has abstract method onError. This method will be called from subscriber.onError(new Throwable());

    EDIT: This is how I would do it. Upon closer look I think the main problem in your code is the early part where you call subscriber.onError even when there's no error. You probably don't need map either because you are technically passing data as-is without manipulation. But I left it in case it is needed later.

         Observable.create(new Observable.OnSubscribe<Application>() {
            @Override
            public void call(Subscriber<? super Application> subscriber) {
                List result = getUserApps();
                if (result != null){
                    for (Application app : result){
                         subscriber.onNext(app);
                    }
                    subscriber.onComplete();
                }else{
                    subscriber.onError(new IOException("no permission / no internet / etc"));
                   //or if this is a try catch event you can pass the exception
                }     
            }
         })
        .subscribeOn(Schedulers.io())//the thread *observer* runs in
        .observeOn(AndroidSchedulers.mainThread())//the thread *subscriber* runs in
        .map(new Func1<Application, String>() {
    
            // Mapping methods are where data are manipulated. 
            // You can simply skip this and 
            //do the same thing in Subscriber implementation
            @Override
            public String call(Application application) {
                return application.getName();
            }
        }).subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {
               Toast.makeText(context, "completed", Toast.LENGTH_SHORT).show();
               //because subscriber runs in main UI thread it's ok to do UI stuff
               //raise Toast, play sound, etc
            }
    
            @Override
            public void onError(Throwable e) {
               Log.e("getAppsError", e.getMessage());
               //raise Toast, play sound, etc
            }
    
            @Override
            public void onNext(String s) {
                listAdapter.add(s);
            }
        });
    
    0 讨论(0)
  • 2021-01-01 10:16

    Here is the newbie response (because I am new in javarx and finally fix this issue) :

    Here is your implementation :

        Observable.create(new Observable.OnSubscribe<RegionItem>() {
                    @Override
                    public void call(Subscriber<? super RegionItem> subscriber) {
                        subscriber.onError(new Exception("TADA !"));
                    }
                })
                .doOnNext(actionNext)
                .doOnError(actionError)
                .doOnCompleted(actionCompleted)
                .subscribe();
    

    In this previous implementation, when I subscribe I trigger the error flow ... and I get an application crash.

    The problem is that you HAVE TO manage the error from the subscribe() call. The "doOnError(...)" is just a kind of helper that clone the error and give you a new place to do some action after an error. But it doesn't Handle the error.

    So you have to change your code with that :

        Observable.create(new Observable.OnSubscribe<RegionItem>() {
                    @Override
                    public void call(Subscriber<? super RegionItem> subscriber) {
                        subscriber.onError(new Exception("TADA !"));
                    }
                })
                .subscribe(actionNext, actionError, actionCompleted);
    

    Not sure about the real explanation, but this is how I fix it. Hope it will help.

    0 讨论(0)
提交回复
热议问题