What is the alternative to AndroidSchedulers.mainThread() in RxJava? - android

Is there a Scheduler api in RxJava synonymous to AndroidSchedulers.mainThread() in RxAndroid.
So If I schedule a task on a new thread and I want to observe it on Java Main Thread, how would I do that?
edit
Below is an example RxSubscription, with system.in commented, the Main thread is killed while the Observable.interval runs on a separate thread. In Android, I can say observeOn(AndroidSchedulers.MainThread) and any operation thereafter would run on the main thread. I am looking for a similar scheduler in Java as AndroidSchedulers is part of RxAndroid.
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import rx.Observable;
public class Main {
public static void main(String[] args) throws InterruptedException, IOException {
Observable<Long> values = Observable.interval(1000, TimeUnit.MILLISECONDS);
values.subscribe(
v -> System.out.println("Received: " + v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
//System.in.read();
}
}

Getting back to the "main" Java thread is currently not possible as there is no blocking Scheduler for RxJava 1.x.
In case you can upgrade to RxJava 2.x, I have a special Scheduler that can be "pinned" to the current thread:
compile "com.github.akarnokd:rxjava2-extensions:0.15.1"
BlockingScheduler
This type of scheduler runs its execution loop on the "current thread", more specifically, the thread which invoked its execute() method. The method blocks until the shutdown() is invoked. This type of scheduler allows returning to the "main" thread from other threads.
public static void main(String[] args) {
BlockingScheduler scheduler = new BlockingScheduler();
scheduler.execute(() -> {
Flowable.range(1, 10)
.subscribeOn(Schedulers.io())
.observeOn(scheduler)
.doAfterTerminate(() -> scheduler.shutdown())
.subscribe(v -> System.out.println(v + " on " + Thread.currentThread()));
});
System.out.println("BlockingScheduler finished");
}

Yes, RxJava has schedulers. To send a message to any thread, you need to have a message loop of some sort waiting for messages from the other threads. In Android this is your Looper. In Java, you'd need to do that yourself. Your Scheduler would then send a message to that thread and do the work in that message response. The mechanism for that depends on how you implement your message queue, but should be fairly trivial.

Related

How to use IntentService thread using RxJava2

I faced with the next situation. I start my code in onHadleIntent method and some part of the code is worked in IntentService thread but the Observable.zip method in getInfoAboutUser() is worked in RxJava thread.
#Override
protected void onHandleIntent(#Nullable Intent intent) {
LOG.debug(Thread.currentThread().getName());
Call<String> call= mRepository.getInfo();
try {
retrofit2.Response<String> response = call.execute();
if (response.isSuccessful()) {
LOG.debug("Response body "+Thread.currentThread().getName());
getInfoAboutUser();
}
}catch(){}
}
public void getInfoAboutUser(){
LOG.debug("getInfoAboutUser "+Thread.currentThread().getName());
Executor e = new Executor() {
#Override
public void execute(#NonNull Runnable runnable) {
LOG.debug(" executor thread");
runnable.run();
}
};
Observable.zip(
Observable.fromIterable(array),
Observable
.interval((mRandom.nextInt(7)+5) * 1000,
TimeUnit.MILLISECONDS,Schedulers.from(e))
.take(array.size()),
new BiFunction<String, Long, String>() {
#Override
public String apply(String s, Long aLong) throws Exception {
LOG.debug("Result "+Thread.currentThread().getName());
return s;
}
}
).flatMapMaybe(new Function<String, MaybeSource<String>>() {
#Override
public MaybeSource<String> apply(String s) throws Exception {
return mRepository.getInfoAboutUser(s);
}
}).subscribeWith(new DisposableObserver<String>() {})
}
mRepository.getInfo() and mRepository.getInfoAboutUser(s) methods I am using without subscribeOn and observeOn!
My log is:
IntentService thread
IntentService thread Response body
IntentService thread getInfoAboutUser
RxSingleScheduler-1 executor thread
RxSingleScheduler-1 Result
etc
What shall i do to use IntentService thread for Observable.zip and Interval methods? I need only IntentService thread
Schedulers.from(e) wraps the Executor in the internal class ExecutorScheduler. If a task is scheduled with a delay and the given Executor is not a ScheduledExecutorService then it will use an internal scheduler to delay the call to e.execute() until the delay is finished.
Because your executor simply immediately executes, it ends up executing on the helper scheduler which is RxSingleScheduler-1.
To solve this you need to choose from the following solutions:
Create a ScheduledExecutorService which correctly dispatches the runnables to the IntentService.
Create a custom Scheduler which dispatches the runnables to the IntentService's Looper.
Use the RxAndroid library to do 2. for you. AndroidSchedulers.from(Looper.myLooper()) will create a scheduler for the IntentService.
Edit: Please do note that IntentService and asynchronous operations don't mix. The service will terminate when handleIntent returns so it is not the a good
way to execute delayed operations like Observable.interval.

Operators after findallAsync().asFlowable() are running on the UI thread

I'm facing with a problem, rxjava operators are running in the UI thread.
I'm using findAllAsync() to get object asynchronously and using asFlowable() to treat them with rxjava operator.
realm.where(Specie.class)
.equalTo("fauna", true)
.findAllAsync().asFlowable()
.filter(new Predicate<RealmResults<Specie>>() {
#Override
public boolean test(RealmResults<Specie> species) throws Exception {
System.out.println("THREAD : " + Thread.currentThread().getId()); // Print 1
return species.isLoaded();
}
})
But in the realm rxjava example they are using observeOn(AndroidSchedulers.mainThread()) , it means the previous operators are running asynchronously otherwise it would be useless.
Link : https://github.com/realm/realm-java/blob/master/examples/rxJavaExample/src/main/java/io/realm/examples/rxjava/animation/AnimationActivity.java
disposable = realm.where(Person.class).findAllAsync().asFlowable()
.flatMap(persons -> Flowable.fromIterable(persons))
.zipWith(Flowable.interval(1, TimeUnit.SECONDS), (person, tick) -> person)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(person -> {
TextView personView = new TextView(AnimationActivity.this);
personView.setText(person.getName());
container.addView(personView);
});
How can I run operators after asFlowable() asynchronously ?
edit : How can I access RealmResults obtained on the UI thread on a
background thread ?
The execution on Schedulers.computation(), so they add observeOn(AndroidSchedulers.mainThread()) to go back to the main thread.
The Realm Async Query API handles the asynchronous evaluation of the query on its own, and the results of that query are passed back by Realm to the UI thread, that is when isLoaded() is true.
To get off the main thread, you can use observeOn(Schedulers.io()) for example.

Query on RxJava thread scheduling

I am new to RxJava2. In the code below, I am unable to understand how is the subscriber working on a background thread, even though the Observable/Flowable is emitting on the main thread and there is no Scheduler specified (using subscribeOn(Schedulers.*) calls). The full code can be found in this github repo.
#OnClick(R.id.btn_start_simple_polling)
public void onStartSimplePollingClicked() {
_log("onStartSimplePollingClicked called on "); //MAIN THREAD
final int pollCount = POLL_COUNT;
Disposable d = Observable
.interval(INITIAL_DELAY, POLLING_INTERVAL, TimeUnit.MILLISECONDS)
.map(this::_doNetworkCallAndGetStringResult)
.take(pollCount)
.doOnSubscribe(subscription -> {
_log(String.format("Start simple polling - %s", _counter)); //MAIN THREAD
})
.subscribe(taskName -> {
_log(String.format(Locale.US,
"Executing polled task [%s] now time : [xx:%02d]",
taskName,
_getSecondHand()));
});
_disposables.add(d);
}
private String _doNetworkCallAndGetStringResult(long attempt) {
try {
_log("_doNetworkCallAndGetStringResult called on "); //BACKGROUND THREAD
if (attempt == 4) {
// randomly make one event super long so we test that the repeat logic waits
// and accounts for this.
Thread.sleep(9000);
}
else {
Thread.sleep(3000);
}
} catch (InterruptedException e) {
Timber.d("Operation was interrupted");
}
_counter++;
return String.valueOf(_counter);
}
Since you did not specify a scheduler on which to subscribe RxJava defaults to a synchronous subscription. So the calls to onSubscribe and doOnSubscribe happen on the main thread.
However the Observable.interval operator requires either an implicit or an explicit scheduler to broadcast the onNext events. Since you did not specify a scheduler it defaults to Schedulers.computation().
After the interval fires it continues to call _doNetworkCallAndGetStringResult on the same computation thread, thus happening in the background.
RxJava by default run syncroniously but some operators as #Kiskae already told you as interval, delay or some others
If you want to run a pipeline asyncroniously you will have to use observerOn which will make run the pipeline in another thread once is put in your pipeline
/**
* Once that you set in your pipeline the observerOn all the next steps of your pipeline will be executed in another thread.
* Shall print
* First step main
* Second step RxNewThreadScheduler-2
* Third step RxNewThreadScheduler-1
*/
#Test
public void testObservableObserverOn() throws InterruptedException {
Subscription subscription = Observable.just(1)
.doOnNext(number -> System.out.println("First step " + Thread.currentThread()
.getName()))
.observeOn(Schedulers.newThread())
.doOnNext(number -> System.out.println("Second step " + Thread.currentThread()
.getName()))
.observeOn(Schedulers.newThread())
.doOnNext(number -> System.out.println("Third step " + Thread.currentThread()
.getName()))
.subscribe();
new TestSubscriber((Observer) subscription)
.awaitTerminalEvent(100, TimeUnit.MILLISECONDS);
}
or use subscribeOn which it will make your pipeline run in the thread that you specify
/**
* Does not matter at what point in your pipeline you set your subscribeOn, once that is set in the pipeline,
* all steps will be executed in another thread.
* Shall print
* First step RxNewThreadScheduler-1
* Second step RxNewThreadScheduler-1
*/
#Test
public void testObservableSubscribeOn() throws InterruptedException {
Subscription subscription = Observable.just(1)
.doOnNext(number -> System.out.println("First step " + Thread.currentThread()
.getName()))
.subscribeOn(Schedulers.newThread())
.doOnNext(number -> System.out.println("Second step " + Thread.currentThread()
.getName()))
.subscribe();
new TestSubscriber((Observer) subscription)
.awaitTerminalEvent(100, TimeUnit.MILLISECONDS);
}
You can see more examples about async rxJava here https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/scheduler/ObservableAsynchronous.java

Schedulers.io() not returning to main thread

I'm using RxParse to parse query's async load but when i subscribe my observable using subscribeOn(Schedulers.io()) my onCompleted method is never called on main thread. Instead of this, my onCompleted method is called inside of worker thread pool. If i use observeOn(AndroidSchedulers.mainThread) everything will work as well, but my onNextMethod will be called on main thread too and I don't want it.
There is something wrong in my code?
Have anything wrong in my code?
ParseObservable.find(myQuery)
.map(myMapFunc())
.subscribeOn(AndroidSchedulers.handlerThread(new Handler()))
.subscribe(
new Subscriber<MyObj>() {
#Override
public void onError(Throwable e) {
Log.e("error","error",e);
}
#Override
public void onNext(T t) {
// ... worker thread (but here is ok)
}
public void onCompleted() {
// ... worker thread again instead of mainThread
}
}
)
);
First you need to understand the difference between subscribeOn() and observeOn(). These are two completely different operators that affect different parts of the Rx chain.
subscribeOn() specifies where your Observable will do its work. It will not affect where onNext(), onError(), and onComplete() execute.
observeOn() specifies where the the callbacks (e.g. onNext()) are executed. It will not affect where your Observable does its work.
All the callbacks will occur on the same thread. You cannot specify that some callbacks occur on one thread and some happen on another through any RxJava APIs. If that is the behavior you desire, you will have to implement it yourself in your callbacks.
Unfortunately the subscription is in the same thread for all methods (onNext, onError and onCompleted
But you can observe in the Schedulers.io() and inside the onNext(T t) method, create a new Observable to listen in the MainThread like this:
ParseObservable.find(myQuery)
.map(myMapFunc())
.subscribeOn(Schedulers.io())
.subscribe(
new Subscriber<MyObj>() {
#Override
public void onError(Throwable e) {
Log.e("error","error",e);
}
#Override
public void onNext(T t) {
Observable.just(t)
.observeOn(AndroidSchedulers.mainThread())
.subscribe((t) -> {
// do something in MainThread
})
}
public void onCompleted() {
// ... worker thread again instead of mainThread
}
}
)
);
I hope it help!
I would recommend using "side action" operators in this case. It seems to me like a slightly more elegant solution than using nested observables:
ParseObservable.find(myQuery)
.map(myMapFunc())
.subscribeOn(AndroidSchedulers.handlerThread(new Handler()))
.doOnCompleted(() -> onCompleteAction())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(value -> onNext(value))
.subscribe();
It is not advisable to subscribe within a subscription.
subscribeOn determines where the Observable chain will start when an observer subscribes to it.
observeOn can be used at different points (and multiple times, if need be) throughout your observable chain to pass control between threads. (You can verify this by checking whether you're on the main thread or not within each of these blocks).
ParseObservable.find(myQuery)
.map(myMapFunc())
// Added this:
.doOnNext(obj -> {
// NOTE: This will happen on your `subscribeOn` scheduler
// Do something with `obj` here while on worker thread
}
.subscribeOn(AndroidSchedulers.handlerThread(new Handler()))
// Added this:
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<>() {
next -> {
// NOTE: This will happen on the main thread
},
error -> {
Log.e("error","error",e);
// NOTE: This will happen on the main thread
},
() -> {
// NOTE: This will happen on the main thread
}
});

When to use AsyncTask and When to use Thread in Android

When to use AsyncTask and When to use Thread as both do work in background and both can manipulate controls in UI Thread by some mechanism..
May this help you:
For long-running tasks, we use Java threads, and Android's native AsyncTask.
Basically Use AsyncTask for:
Simple network operations which do not require downloading a lot of data
Disk-bound tasks that might take more than a few milliseconds
And Use Java threads for:
Network operations which involve moderate to large amounts of data (either uploading or downloading)
High-CPU tasks which need to be run in the background
Any task where you want to control the CPU usage relative to the GUI thread
For more information refer
Mohit's answer Click Here
Edit:
Service is like an Activity but has no interface. Probably if you want to fetch the weather for example you won't create a blank activity for it, for this you will use a Service. Service is access to a Context object which has an independent life cycle. This allows for reuse of common code by many activities and, in the case of public or exposed services in many applications.
A Service runs on the main thread of the calling Component’s process by default (and hence can degrade responsiveness and cause ANRs), hence you should create a new Thread to perform long running operations.
A Thread is a Thread, probably you already know it from other part. You need to know that you cannot update UI from a Thread. You need to use a Handler for this and stopping a thread sometime become problematic also. A thread is a mechanism for doing work without blocking other work...
A service does not imply a thread and a thread does not imply a service. Both are different from eachother..
An AsyncTask is an intelligent Thread that is advised to be used. Intelligent as it can help with it's methods, and there are two methods that run on UI thread, which is good to update UI components.
AsyncTask is just a "helper" class provided with Android SDK to make it easier to skip to the UI thread after the background task is finished. It is built over the standard Java threading API. It does not give antyhing that cannot be done with Threads only. It addresses the common scenario of switching between the short task run background thread and UI thread.
Generally it is convenient to use AsyncTask when you must "skip back" to UI thread when the background task is done or when you have to give some feedback to UI thread during task execution. Otherwise it's just overhead.
You are not forced to use AsyncTask. If you as a developer prefer using Threads directly or Futures you may use it and skip to UI thread on your own manually after the background task is done.
EDIT:
Some other answers here suggest that using AsyncTask should be limited to short tasks. Allegedly because it uses a common pool. However it is no longer true since API Level 11 (so, for quite a long time). You can use executeOnExecutor instead of execute to execute AsyncTask's in dedicated thread pool. See http://developer.android.com/reference/android/os/AsyncTask.html#executeOnExecutor%28java.util.concurrent.Executor,%20Params...%29
Because examples are usually more communicative look at the example below.
Let's assume that we have a static function to do some heavy task and a TextView which we want to display progress and final status of the task declared as below:
static Object doHeavyTask(String string) throws Exception;
TextView progressInfo;
Execution of the task in background thread using async task would look like:
new AsyncTask<String, Integer, Exception>() {
#Override
protected Exception doInBackground(String... params) {
for (int i = 0; i < params.length; i++) {
try {
doHeavyTask(params[i]);
} catch (Exception e) {
return e;
}
publishProgress(i, params.length);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
progressInfo.setText("Executed " + values[0] +
" of " + values[1] + " tasks.");
}
#Override
protected void onPostExecute(Exception result) {
if (result == null) {
progressInfo.setText("Heavy background job done successfully!");
}
else {
progressInfo.setText("Heavy background job failed!" +
"Exception message: " + result.getMessage());
}
}
}.execute("input1", "input2", "input3");
Exactly the same can be achieved with Thread:
final Handler handler = new Handler(Looper.getMainLooper());
final String[] params = { "input1", "input2", "input3" };
new Thread() {
#Override
public void run() {
for (int i = 0; i < params.length; i++) {
try {
doHeavyTask(params[i]);
} catch (final Exception e) {
handler.post(new Runnable() {
#Override
public void run() {
progressInfo.setText("Heavy background job failed!" +
"Exception message: " + e.getMessage());
}
});
return;
}
final int currentIndex = i;
handler.post(new Runnable() {
#Override
public void run() {
progressInfo.setText("Executed " + currentIndex +
" of " + params.length + " tasks.");
}
});
}
handler.post(new Runnable() {
#Override
public void run() {
progressInfo.setText(
"Heavy background job done successfully!");
}
});
}
}.start();
As you see above using the AsyncTask is simply a bit more convenient. But there is no other advantage, just this convenience :).
If you prepared your own task encapsulating Thread (and a Handler to skip back to the UI thread) then maybe your class will be more efficient/comfortable for you to use.
That's all :).
You can run multiple threads concurrently. But asynctask is queued, meaning it is running one task at a time.

Categories

Resources