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();
}
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 using rxjava with retrofit. In the following code the subscribeOn() and observeOn() keeps running. The App terminates and launched by itself continuously.
disposable = api.getUsers("135")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
users -> showResult(users)
})
If I dispose right after the above it won't fetch complete data. So my question is when to dispose dispoable or how to know when subscribeOn() and observeOn() has completed it's task.
either you can dispose in onDestroy() of your Activity.
or you can use DisposableSingleObserver for good , like this :
Disposable disposable = yourApi.subscribeWith(new DisposableSingleObserver<List<String>>() {
#Override
public void onSuccess(List<String> values) {
// work with the resulting values
}
#Override
public void onError(Throwable e) {
// handle the error case
}
});
and then after you use the result (in this example case when you no longer need the values(api response) you can call dispose
disposable.dispose();
best place to dispose an observer will be in onDestory() , this will be the place where you no longer will be needing api result:
protected void onDestroy(){
super.onDestroy();
disposable.dispose();
}
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
I am researching into RxJava/RxAndroid. I decided to create Observable via Observable.fromCallable method because of it gives us two important things:
The code for creating the emitted value is not run until someone subscribes to the Observerable
The creation code can be run on a different thread.
I have wrote the sample as below:
private void testObservableFromCallable() {
Observable<String> stringObservable = Observable.fromCallable(new Callable<String>() {
#Override
public String call() throws Exception {
return "Hello";
}
});
Subscription subscription = stringObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
Log.d("LOG_TAG", "Thread name: " + Thread.currentThread().getName());
textView.setText(s);
}
});
}
Every things are ok. It work fine and log tag show thread name is main. It means onNext() method be called on mainThread() and textView be accessed properly.
Now what am I confusing is when I remove this line observeOn(AndroidSchedulers.mainThread()) or just change it to observeOn(Schedulers.io()). Both of two cases the log tag show thread name is RxIoScheduler. That is not main thread, but the app compile with no error and textView show the text "Hello" on the screen.
Anyone help me explain why am I able to access to the view outside main thread?.
Thanks so much!
The framework usually does not do anything to check that you're really on the main thread. As a caller, it's your responsibility.
Some but not all UI widget access on non-main thread lead to a crash. Here you're being "lucky" that the thread problem goes undetected with your method call.
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.