Search code examples
androidandroid-layoutrx-javarx-androidandroid-mvp

Access to items layout from RxAndroid?


I am using the code below:

    mCompositeDisposable.add(myObservable(IdLang, shortTermCoursesModels)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeWith(new DisposableObserver<String>() {
                @Override
                public void onComplete() {
                }

                @Override
                public void onError(Throwable e) {
                }

                @Override
                public void onNext(String string) {
                    listenerCoursesListItemService.adapterHideProgress();
                }
            }));

And:

private Observable<String> myObservable(String IdLang, List<GetShortTermCoursesModel> shortTermCoursesModels) {
    return Observable.defer(new Callable<ObservableSource<? extends String>>() {
        @Override
        public ObservableSource<? extends String> call() throws Exception {
            listenerCoursesListItemService.adapterShowProgress();
            for (int i = 0; i < 900000; i++) {
                Log.i("WWWWWWWW", "A " + i);
            }
            return Observable.just("ok");
        }
    });

But get me the error below:

 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

How can I access to UI from RxAndroid.

My error is here:

listenerCoursesListItemService.adapterShowProgress();
listenerCoursesListItemService.adapterHideProgress();

Solution

  • The reason is you are trying to show progress ->

    listenerCoursesListItemService.adapterShowProgress(); 
    

    inside call() method which actually runs on different thread (Schedulers.io()) and not UI thread (AndroidSchedulers.mainThread()).

    Instead you can show progress inside doOnSubscribe() method and dismiss it inside onComplete(). Both methods will be called on UI thread. Updated your code below for reference,

    mCompositeDisposable.add(myObservable(IdLang, shortTermCoursesModels)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .doOnSubscribe(new Consumer<Disposable>() {
            @Override
            public void accept(@NonNull Disposable disposable) throws Exception {
                listenerCoursesListItemService.adapterShowProgress();
            }
        })
        .doFinally(new Action() {
            @Override
            public void run() throws Exception {
               listenerCoursesListItemService.adapterHideProgress();
            }
        })
        .subscribeWith(new DisposableObserver<String>() {
            @Override
            public void onComplete() {
            }
    
            @Override
            public void onError(Throwable e) {
            }
    
            @Override
            public void onNext(String string) {
            }
        }));
    

    And:

    private Observable<String> myObservable(String IdLang, List<GetShortTermCoursesModel> shortTermCoursesModels) {
        return Observable.defer(new Callable<ObservableSource<? extends String>>() {
            @Override
            public ObservableSource<? extends String> call() throws Exception {
                for (int i = 0; i < 900000000; i++) {
                    Log.i("WWWWWWWW", "A " + i);
                }
                return Observable.just("ok");
            }
        });
    }
    

    Inside onNext() you would get the string you return from call() method.