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
Related
I'm using RxAndroid to marshal a string from a background thread into the main thread, and do something with that string on that main thread:
String stringFromDatabase = readFromDatabase();
Observable.just(stringFromDatabase)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
#Override
public void accept(String string) throws Exception {
webViewFragment.onInjectMessage(string, null);
}
});
Android Studio is highlighting the entire Observable.just... command chain in yellow, telling me that "The result of subscribe is not used", when I hover on it.
If I add .dispose() to the end of the chain, the highlighting disappears, but the webViewFragment.onInjectMessage(string, null); code is no longer executed.
I noticed that I can remove the highlighting by adding a #SuppressLint("CheckResult") annotation to the entire method.
Is this something like a warning which can be safely ignored, or am I creating some kind of a memory leak or other problem here? Is this a bad practice?
You have to dispose it to avoid memory leak. Try to dispose inside onDestroy
Disposable disposable;
String stringFromDatabase = readFromDatabase();
disposable = Observable.just(stringFromDatabase)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
#Override
public void accept(String string) {
webViewFragment.onInjectMessage(string, null);
}
});
#Override
protected void onDestroy() {
super.onDestroy();
disposable.dispose();
}
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.
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'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().