I created simple activity with infinity progres bar, and I'am trying to run time consuming method using RxJava to prevent UI thread from blocking, but everytime UI thread is blocked. I think my solution has problem with emitting Observable. Can anyone help me? I'am begginer in RX.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void doSomething(View view) {
doHeavyStuff()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Action1() {
#Override
public void call(Object o) {
Toast.makeText(getApplicationContext(), "FINISHED", Toast.LENGTH_SHORT).show();
}
})
.subscribe();
}
private Observable doHeavyStuff() {
for (int i = 0; i < 999999999; i++) {
for (int j = 0; j < 2; j++) {
}
}
return Observable.just(1);
}
With RxJava2 a possible solution is:
Version with lambdas:
Single.fromCallable(() -> loadInBackground())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((resultObject) -> { updateUi(resultObject) });
Version without lambdas:
Single.fromCallable(new Callable<Object>() {
#Override
public Object call() throws Exception {
return loadInBackground();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
#Override
public void accept(Object resultObject) throws Exception {
updateUi(resultObject);
}
});
Example methods used above:
private Object loadInBackground() {
// some heavy load code
return resultObject;
}
private void updateUi(Object resultObject) {
// update your Views here
}
According to docs
Deprecated:
fromFunc0
Unnecessary now that Func0 extends Callable. Just call fromCallable(java.util.concurrent.Callable) instead.
So you could make the call in this way:
Observable.fromCallable(new Callable<Object>() {
#Override
public Object call() throws Exception {
return someMethod();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Object>() {
#Override
public void call(Object object) {
}
});
Your doHeavyStuff() executes computation on calling thread, you just wrap your result into Observable.
In order to wrap computation into observable you should use defer
Observable.defer(new Func0<Observable<Integer>>() {
#Override
public Observable<Integer> call() {
return Observable.just(doHeavyStuff());
}
});
then you can specify threads by subscribeOn and observeOn methods
kotlin use below code to work in background
Single.fromCallable {
// method that run in background
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe()
Also, you can use RxJavaAsyncUtil:
compile 'io.reactivex:rxjava-async-util:0.21.0'
Code:
Observable.fromFunc0(() -> doHeavyStuff())
Related
Hi I just start learning Reactive programming using RxJava2.
How do I create a task that runs in the background thread and then complete on main thread using RxJava2.
Example in Android we use AsyncTask just like example below
private class MyTask extends AsyncTask<String, Integer, Boolean>
{
#Override
protected Boolean doInBackground(String... paths)
{
for (int index = 0; index < paths.length; index++)
{
boolean result = copyFileToExternal(paths[index]);
if (result == true)
{
// update UI
publishProgress(index);
}
else
{
// stop the background process
return false;
}
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values);
int count = values[0];
// this will update my textview to show the number of files copied
myTextView.setText("Total files: " + count);
}
#Override
protected void onPostExecute(Boolean result)
{
super.onPostExecute(result);
if (result)
{
// display a success dialog
ShowSuccessAlertDialog();
}
else
{
// display a fail dialog
ShowFailAlertDialog();
}
}
}
For this example I want to pass in a Array / ArrayList of Strings and it is use to execute some method in the background thread. Then every success result will update my TextView (UI thread). If one of the process fail, I want it to stop directly. Lastly I want to update my Views when the process has completed.
I only manage to get this far
Observable.just(paths).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ArrayList<String>>()
{
private boolean result;
#Override
public void onSubscribe(Disposable d)
{
}
#Override
public void onNext(ArrayList<String> paths)
{
for (int index = 0; index < paths.size(); index++)
{
result = copyFileToExternal(paths[index]);
if (result == true)
{
// cant update UI because is in background thread
myTextView.setText("Total files: " + index);
}
else
{
// end the loop
break;
}
}
}
#Override
public void onError(Throwable e)
{
}
#Override
public void onComplete()
{
if (result)
{
// cant display because it is still in background thread
ShowSuccessAlertDialog();
}
else
{
// cant display because it is still in background thread
ShowFailAlertDialog();
}
}
});
I looked at a few tutorials but can't seem to find the answer.
Thanks in advance for the help
I would do something like this:
Observable.fromArray(getPaths())
.map(path -> copyFileToExternal(path))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aInteger -> Log.i("test", "update UI"),
throwable -> ShowFailAlertDialog),
() -> ShowSuccessAlertDialog());
A good idea is usually to have a "handler" for controlling the subscription to your observer. So that, when you need to stop your background task (for example because the user left the Activity), you can use it. For this purpose you can use subscribeWith instead of subscribe, that receive as input a ResourceObserver: in this way you get a Disposable.
Disposable subscription = Observable.fromArray(getPaths())
.map(path -> copyFileToExternal(path))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new ResourceObserver<Integer>() {
#Override
public void onNext(#NonNull Integer index) {
Log.i("test", "update UI");
}
#Override
public void onError(#NonNull Throwable e) {
ShowFailAlertDialog();
}
#Override
public void onComplete() {
ShowSuccessAlertDialog();
}
});
When you need to stop the task you can just call:
subscription.dispose();
I'm new at this, but I got a working example..
//Observable
Observable.just("input_parameter")
.subscribeOn(Schedulers.io())//creation of secondary thread
.map(new Function<String, String>() {//<input obj,return obj>
#Override
public String apply(String cad){//input obj
Log.d(TAG,"thread :"+Thread.currentThread().getName());
//runs in a secondary thread
return "result text: "+doLongNetworkOperation();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(MyObserver);//now this runs in main thread
And MyObserver:
//Observer
Observer MyObserver = new Observer() {
#Override
public void onSubscribe(Disposable d) {
Log.d(TAG,"onSubscribe thread:"+Thread.currentThread().getName());
}
#Override
public void onNext(Object value) {
Log.d(TAG,"on next, valor:<<"+value.toString()+">> \n nombre hilo:"+Thread.currentThread().getName());
}
#Override
public void onError(Throwable e) {
Log.d(TAG,"error "+e.toString());
}
#Override
public void onComplete() {
Log.d(TAG,"onCompleted thread:"+Thread.currentThread().getName());
}
};
Plz, let me know if this works for you.
In the code below, the loadMoreStrings() method is have it's call() method execute before the getLabelsFromServer() completes. I'm still learning RxJava but I just can't get this to run properly.
private void fetchLabels() {
listObservable = Observable.fromCallable(new Callable<List<String>>() {
#Override
public List<String> call() {
return apiService.getLabelsFromServer();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
loadMoreStrings();
}
#Override
public void loadMoreStrings() {
stringListObservable.subscribe(new Action1<List<String>>() {
#Override
public void call(List<String> label) {
myStrings.addAll(label);
}
});
}
Because Observable type is lazy and it's not going to emit any items until you subscribe to it.
From code that you provided, you're not subscribing to listObservable. So it completes immediately and your loadMoreStrings() method is getting called.
I have to execute 3 API calls in the sequence and to do so
I use observable.concatMap(new Func1<>...)
and at the last one I have a subscriber to change activity
However I want to update progressBar in UI thread to let user know that part of task is done.
private void getAllData() {
updateUserTask(
getUserScheduleObservable(
getCurrentUserObservable()));
}
private void updateUserTask(Observable<TaskWrapper> observable) {
wrapObservable(observable)
.subscribe(new Subscriber<TaskWrapper>() {
#Override
public void onNext(TaskWrapper taskWrapper) {
openCurrentFragment();
hideProgressIndicators();
}
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
}
});
}
private Observable<TaskWrapper> getUserScheduleObservable(Observable<ScheduleWrapper> observable) {
return observable.concatMap(
scheduleWrappers1 -> apiManager.getRouteObservable(vehicleDeliveryAreaRiderBundle.getVehicle().getId()));
}
private Observable<ScheduleWrapper> getCurrentUserObservable() {
return apiManager.getUserObservable().concatMap(
user -> apiManager.getCurrentScheduleObservable()
);
}
I think that you are looking for something like this.
public class ExampleUnitTest {
#Test
public void testSample() throws Exception {
Observable<String> first = Observable.just("First");
Observable<String> second = Observable.just("Second");
Observable<String> third = Observable.just("Third");
Observable.concat(first, second, third)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(this::updateProgress)
.subscribe();
}
private void updateProgress(String s) {
System.out.println(String.format("Notify your progress that %s ended", s));
}
}
Just concatenating those observables, you can achieve the expected result.
Hope that it helps.
Best regards.
I'm trying to implement an Observable/Subscriber with RxJava on the onPostExecute() of an AsyncTask and I don't get how to make the connection.
I create the Observable in the onPostExecute method. I want MyFragment to subscribe to this. How do I set this up?
public class LoadAndStoreDataTask extends AsyncTask<String, Integer, String> {
...
#Override
protected void onPostExecute(String result) {
// create the observable
Observable<String> myObservable = Observable.create(
new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext(result);
subscriber.onCompleted();
}
}
);
myObservable.subscribe(mySubscriber);
}
}
public class MyFragment extends Fragment {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Subscriber<String> mySubscriber = new Subscriber<String>() {
#Override
public void onNext(String s) { System.out.println(s); }
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) { }
};
}
...
}
Actually RxJava is supposed to replace AsycTask. In fact I can say with confidence that AsyncTask is a subset of RxJava.
In RxJava, a Subscriber would be analogous to AsyncTask.progressUpdate or onPostExecute and Observable to the process in doInBackground. Data are emitted from Observable to Subscriber and any alteration in this stream is done with mapping methods. You probably don't need mapping now so I would reconfigure my RxJava like this:
Observable<String> myObservable = Observable.create(
new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
try{
String res = ...//your original doInBackground
subscriber.onNext(res);
// onNext would be comparable to AsyncTask.onProgressUpdate
// and usually applies when backgorund process runs a loop
subscriber.onCompleted();
}catch (SomeException e){
// if the process throws an exception or produces a result
// you'd consider error then use onError
subscriber.onError(e);
}
}
}
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) // If subscriber runs on UI thread
.subscribe(new Subscriber<String>() {
#Override
public void onNext(String response) {
// result from Observable.onNext. The methods below correspond
// to their Observable counterparts.
}
#Override
public void onCompleted() {}
#Override
public void onError(Throwable e) {}
});
AndroidSchedulers is available in RxAndroid. To use it add this line to build.gradle :
compile 'io.reactivex:rxandroid:0.24.0'
I'm looking a way to define order(?) of observers.
#GET("/get_user_msgs")
Observable<PrivateMessagesResponse> getPrivateMessages(#QueryMap Map<String, String> params);
For example I gave a Observable from my Rest API created by Retrofit.
In my ListView I'm observing this Observable.
api.getPrivateMessages(params).subscribe(new Observer());
I also have an API wrapper for my Espresso tests and I'm subscribing to same Observable there. This way observer in API wrapper is called first and only then observer in ListView
is called.
public class IdlingWrapper implements Api, IdlingResource {
....
public IdlingWrapper(Api realApi) {
this.realApi = realApi;
}
...
public Observable<PrivateMessagesResponse> getPrivateMessages(#QueryMap Map<String, String> params); {
counter.incrementAndGet();
return wrapObservable(realApi.getPrivateMessages(params));
}
protected <T> Observable<T> wrapObservable(final Observable<PrivateMessagesResponse> observable) {
//what to do here?
}
}
Is there a way to force some observer to be notified after all others are done? Or something similar in that matter?
Something like
Observable observable = getObservable();
observable.subscribeAsLast(new LastObserver());
observable.subscribe(new ObserverA());
observable.subscribe(new ObserverB());
And so that ObserverA would be notified first, then ObserverB and only then LastObserver.
Or any other approach where I could find out when all registered observers were notified and completed.
I'm not exactly sure what you are trying to do in IdlingWrapper, but I think the current implementation is very fragile.
I think the most important thing that needs to happen is to guarantee the observable can only be called once.
Here is a quick implementation to demonstrate that as well as my implementation of wrapObservable.
public class Test {
private static int counter = 0;
private static final List<Observable<?>> list = Collections.synchronizedList(new ArrayList<>());
protected static <T> Observable<T> wrapObservable(final Observable<T> original) {
// run atleast once???
synchronized (list) {
list.add(original);
}
return Observable.create(new Observable.OnSubscribe<Void>() {
#Override
public void call(Subscriber<? super Void> subscriber) {
synchronized (list) {
counter++;
if (!list.contains(original)) {
subscriber.onError(new Exception("You can only subscribe once!"));
return;
}
list.remove(original);
}
// Sleep to make it easier to see things happening...
try {
Thread.sleep(3000);
} catch (InterruptedException ignored) {
}
subscriber.onCompleted();
}
}).flatMap(new Func1<Void, Observable<? extends T>>() {
#Override
public Observable<? extends T> call(Void o) {
return original;
}
}).finallyDo(new Action0() {
#Override
public void call() {
synchronized (list) {
counter--;
if (list.size() == 0 && counter == 0) {
System.err.println("finally");
}
}
}
});
}
public static void main(String[] args) throws InterruptedException {
for(int i = 0; i < 10; i++) {
// running in io thread for simulating async call.
Observable<String> test = wrapObservable(Observable.from("TEST!!!!!!")).subscribeOn(Schedulers.io());
test.subscribe(new Observer<String>() {
#Override
public void onCompleted() {
System.err.println("completed");
}
#Override
public void onError(Throwable e) {
System.err.println("error");
}
#Override
public void onNext(String s) {
System.err.println("next");
}
});
// example of calling the same observable twice.
test.subscribe(new Observer<String>() {
#Override
public void onCompleted() {
System.err.println("completed");
}
#Override
public void onError(Throwable e) {
System.err.println("error");
}
#Override
public void onNext(String s) {
System.err.println("next");
}
});
}
Thread.sleep(10000);
}
}
It seems, that this worked just fine.
protected <T> Observable<T> wrapObservable(final Observable<T> original) {
return Observable.create(new Observable.OnSubscribeFunc<T>() {
#Override
public Subscription onSubscribe(final Observer<? super T> t1) {
original.subscribe(new Observer<T>() {
#Override
public void onCompleted() {
t1.onCompleted();
uiThreadHandler.post(new Runnable() {
#Override
public void run() {
counter.decrementAndGet();
notifyIdle();
}
});
}
#Override
public void onError(Throwable e) {
t1.onError(e);
uiThreadHandler.post(new Runnable() {
#Override
public void run() {
counter.decrementAndGet();
notifyIdle();
}
});
}
#Override
public void onNext(T args) {
t1.onNext(args);
}
});
return Subscriptions.empty();
}
});
}
If you want to just use built in RxJava methods to order your observers, you can use flatMap and range to turn each item into multiple items each with a priority and then filter on priority. Observers are ordered based on how they filter.
Here's a trivial example:
Observable<Pair<Integer, Object>> shared = RxView.clicks(findViewById(R.id.textView))
.flatMap(c -> Observable.range(0, 2).map(i -> Pair.create(i, c)))
.share();
shared.filter(p -> p.first == 1)
.map(p -> p.second)
.doOnSubscribe(c -> Log.d(TAG, "first subscribed doOnSubscribe"))
.subscribe(c -> Log.d(TAG, "first subscribed onNext"));
shared.filter(p -> p.first == 0)
.map(p -> p.second)
.doOnSubscribe(c -> Log.d(TAG, "second subscribed doOnSubscribe"))
.subscribe(c -> Log.d(TAG, "second subscribed onNext"));
If you are doing this all over the place