After onError, my observable stops working. How can I avoid that?
Here is my autocomplete observable and subscription code:
public void subscribeAutoComplete() {
autoSubscription = RxTextView.textChangeEvents(clearableEditText)
.skip(1)
.map(textViewTextChangeEvent -> textViewTextChangeEvent.text().toString())
.filter(s -> s.length() > 2)
.debounce(400, TimeUnit.MILLISECONDS)
.flatMap(text -> autoCompleteService.getAutoCompleteTerms(text)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<String>>() {
#Override
public void onCompleted() {
Log.d("rx", "oncomplete");
}
#Override
public void onError(Throwable t) {
Log.e("rx", t.toString());
}
#Override
public void onNext(List<String> strings) {
autoAdapter = new ArrayAdapter<>(MainActivity.this,
android.R.layout.simple_dropdown_item_1line, strings);
clearableEditText.setAdapter(autoAdapter);
clearableEditText.showDropDown();
}
});
compositeSubscriptions.add(autoSubscription);
}
It's simple, just ignore the errors:
autoCompleteService.getAutoCompleteTerms(text).onErrorResumeNext(Observable.empty())
Note that this is potentially dangerous, as you'll ignore all errors; in this case it's probably OK, but be careful of overusing this.
Using tryOnError works for me and it will call error inside subscribe() as well without getting UndeliverableException, app stop running or need of RxJavaPlugins.setErrorHandler which will make UI related more difficult to handle.
Related
I am new to RxAndroid and tried the same with Room database. But the problem is that when inserting data into a database, then the progress bar that I am showing getting blocked and being sluggish. I referred this blog for the project
public void insertBillPayments(final CallBackParams params,
BillPaymentsOffline... payments) {
Completable.fromAction(() -> db.daoAccess().insertBillPayments(payments))
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onComplete() {
params.getCallback().onOrderAdded(params);
}
#Override
public void onError(Throwable e) {
params.getCallback().onDataNotAvailable(params);
}
});
}
Please correct me if I am doing anything wrong.
This code seems fine, but I would recommend that you switch your observeOn and subscribeOn calls for clarity as subscribeOn applies to the stream and observeOn applies to the emitted values and functions applied after it.
http://reactivex.io/documentation/operators/observeon.html
just like this sample
Observable.fromCallable(() -> okHttp.getDataFromNet(page))
.subscribeOn(Schedulers.io())
.doOnSubscribe(()->{adapter.loadmore})
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
adapter.stopLoad();
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onNext(String s) {
Log.e("fail","fail");
adapter.add();
}
});
I find onNextwill be called two times in this case.If i add Log.e() in
onCompleted(),it also will called two times.What is wrong about my code.What is the reason that if a method will be called in Subscriber ,then I add doOnSubscribe() it will be called two times。
//progressbarAdapter extends Recyclerview.Adapter
static final int LOADING_TYPE = -1;
private boolean isLoading = false;
public void loadingMore(){
isLoading = true;
notifyItemInserted(getItemCount());
// size = index +1
}
public void loadingEnd(){
notifyItemRemoved(getItemCount());
isLoading = false;
}
#Override
public int getItemCount() {
return getDataCount() + (isLoading ? 1: 0);
}
#Override
public int getItemViewType(int position) {
if (position == getDataCount() && !isError){
return LOADING_TYPE;
}else {
return getExtItemViewType(position);
}
}
the real reason
when adapter.notify it will trigger scroll methods,so it will be called two times. I am sorry for that I asked a bad question.
please have a look how to use observeOn and subscribeOn. There can only be one subscribeOn for an observable. If you use multiple, the last one wins. Use observeOn to switch threads between pipelines and subscribeOn to specify the thread which will create the observable.
I transformed your given code in order to use it in a test. I only get one onNext-call.
Problem: getting called two times.
This may be because of wrong usage of the observable somewhere else in the code by flatMap or multiple subscriptions to observable. Please provide more context.
Testenvironment: IntelliJ Idea 2017 EAP, io.reactivex:rxjava:1.2.1
#Test
public void name() throws Exception {
Observable<String> doOnSub = Observable.just("1")
.subscribeOn(Schedulers.io())
.doOnSubscribe(() -> {
System.out.println("doOnSub");
})
.subscribeOn(Schedulers.computation())
.observeOn(Schedulers.computation());
TestSubscriber<String> objectTestSubscriber = TestSubscriber.create();
doOnSub.subscribe(objectTestSubscriber);
objectTestSubscriber.awaitTerminalEvent();
objectTestSubscriber.assertValues("1");
}
I wrote a method to print the output from flatMap (Pseudo code):
Observable.just(...).repeat()
.flatMap( return Observable.just([double]))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Double>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
tvConfidence.setText(e.getMessage());
}
#Override
public void onNext(Double aDouble) {
tvConfidence.setText("Confidence :" + aDouble);
}
});
When I run these code, it works a few seconds but after a few seconds, it would not run onto the onNext method again. I don't know why, because I debug the code, it will run the Observable.just(double), and the value always changed but it would not execute the code setText to refresh the textView.
My guess is that due to that particular flatMap overload, you eventually start to accumulate a lot of just because flatMap is unbounded-in. Try with flatMap(f, 1) to limit the concurrency level.
I'm using a RxAndroid observable to retrieve some object (String in this case). My service looks like this:
public Observable<String> getRandomString() {
return Observable.create(new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
//code to retrieve result
subscriber.onNext("this is a string");
subscriber.onCompleted();
}
});
}
I subscribe in my presenter and post the result to the view:
public void loadRandomString() {
Observable<String> observable = mService.getRandomString();
observable
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.newThread())
.subscribe(new Subscriber<String>() {
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) {
mMainView.onError(e.getLocalizedMessage());
}
#Override
public void onNext(String string) {
//do something with string
}
});
}
This works fine and all, but I want this operation to be periodically (every x minutes). I could use a Timer or ScheduledThreadPoolExecutor to do this over and over again but i'd like to see if there is some solution within the realm of RxAndroid. I found some old solutions from 2013 but a lot of the code is deprecated at this time. Is this possible using some kind of recursion, or can I achieve this in a more elegant way?
Thanks in advance!
What you probably want is Observable.interval(). It emits on a timed interval. You can then flatmap that into your Observable<String>, like so:
Observable.interval(3, TimeUnit.MINUTES)
.flatMap(new Func1<Long, Observable<String>>() {
#Override
public Observable<String> call(Long ignore) {
return getRandomString();
}
})
.subscribe(...insert your subscriber here...);
That said - if you're going to be doing this every few minutes, you might be better off looking into AlarmManager or JobScheduler, since chances are users won't be focused on your app for that long of a period of time.
As an aside, it'd be much easier to use Observable.just("this is a string") than Observable.create().
I have an Observable that does something without the need to emit a value. Also I have a list of objects I want the Observable to work with. So for all elements in this list: doSomething()
Observable.from(uris)
.flatMap(new Func1<Uri, Observable<Void>>() {
#Override
public Observable<Void> call(Uri uri) {
return createDoSomethingObservable(uri);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<Void>() {
#Override
public void onCompleted() {
Log.d(TAG, "completed");
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(Void aVoid) {
Log.d(TAG, "next");
}
});
And the method that creates the Observable:
Observable<Void> createDoSomethingObservable(final Uri uri) {
return Observable.create(new Observable.OnSubscribe<Void>() {
#Override
public void call(Subscriber<? super Void> subscriber) {
//doSomething
subscriber.onNext(null);
subscriber.onCompleted();
}
});
}
Now when I run this with a List with 3 elements I get:
next
next
next
completed
which is good, because that is what I wanted, but I don't know why it's working. First I started to just call onComplete, because in the end the observable does its job and completes. But then of course onNext is never called on the subscriber. The same goes for the other way round.
So my questions are:
Why is onComplete only called for the last list element?
Is there a better way to solve this?
onComplete is called for the last element because that's when the earliest observable in the chain (from(uris)) has finished.
It's expected that your observables emitted from flatMap will call onComplete. Once that's done (and call has returned), then the next emission from from can be worked on. Once from has finished emitting observables, it calls onComplete and the chain is finished, effectively.
I think, that small code helps you to understand behavior of onNext( ) and onComplete().
Suppose, you have an List<Uri>. Let's transform it to Observable<Uri> manually.
public static Observable<Uri> getUries(List<Uri> uriList){
return Observable.create(new Observable.OnSubscribe<Uri>() {
#Override
public void call(Subscriber<? super Uri> subscriber) {
for(Uri uri : uriList){
subscriber.onNext(uri);
}
subscriber.onCompleted();
}
});
}
Or using Lambda expressions:
public static Observable<Uri> getUries(List<Uri> uriList){
return Observable.create(subscriber -> {
for(Uri uri : uriList){
subscriber.onNext(uri);
}
subscriber.onCompleted();
});
}
As you can see, we are iterating input list, and call onNext( ) for every element, and when we finished transforming our List to Observable, we called onComplete()
P.S.
This code just a demonstration, please, never use it to transfor List to Observable. Use operator Observable.from() for it.
UPDATE:
Operator from( ) implementation:
...
while (true) {
if (o.isUnsubscribed()) {
return;
} else if (it.hasNext()) {
o.onNext(it.next());
} else if (!o.isUnsubscribed()) {
o.onCompleted();
return;
} else {
// is unsubscribed
return;
}
}
...
link:https://github.com/ReactiveX/RxJava/blob/1.x/src/main/java/rx/internal/operators/OnSubscribeFromIterable.java#L75-L87
onComplete (same as onError) is called only once during observable chain, it is the way that rxjava is implemented
I think that your approach is correct, so better way is not needed.