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().
Related
I am using retrofit and Rxjava to handle api calls for my mvvm android application. Based on some tutorial, i am currently using RxJava like this.
ViewModel.java
CompositeDisposable disposable = new CompositeDisposable();
private void fetchTodolist(){
loading.setValue(true);
disposable.add(
service.getToDoList("A1833")
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver<ApiResponse<ArrayList<TodoItem>>>() {
#Override
public void onSuccess(ApiResponse<ArrayList<TodoItem>> value) {
if(value.getStatus() == 200){
//on call success code
} else {
//on call rejected code
}
}
#Override
public void onError(Throwable e) {
// on call error code
}
})
);
}
And now i want to cache the result of the api call on successful call into room database. So i need to use another async method and tried to reuse the new thread i created before. And here's the code.
private void fetchTodolist(){
loading.setValue(true);
Scheduler a = Schedulers.newThread();
disposable.add(
service.getToDoList("A1833")
.subscribeOn(a)
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver<ApiResponse<ArrayList<TodoItem>>>() {
#Override
public void onSuccess(ApiResponse<ArrayList<TodoItem>> value) {
if(value.getStatus() == 200){
a.scheduleDirect(new Runnable() {
#Override
public void run() {
long inserted = dao.insert(value);
}
});
} else {
//on call rejected code
}
}
#Override
public void onError(Throwable e) {
// on call error code
}
})
);
}
I wonder if it is a bad practice and will lead to a serious problem. And if so, what's the alternative.
Schedulers uses cached references thus newThread() returns the same Scheduler instance.
Schedulers.newThread() == Schedulers.newThread()
Generally you should avoid using newThread because it creates a new thread for every application of the operator. So if you run the sequence multiple times, new worker threads are created and dismissed without any kind of reuse. This is especially true for newThread().scheduleDirect which will start a new thread just for that single runnable and stop it afterwards.
It is recommended you use Schedulers.io() for IO operations so that those underlying worker threads are reused as much as possible later.
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
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.
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 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.