Say I have a method like the code below, in which a List is flatMapped to individual strings, each of which has some expensive operation applied to them. Is there any way to parallelise the expensive operations, in the same way that I'd use parallelStream() in Java 8?
final List<String> names = new ArrayList<String>() {{
add("Ringo");
add("John");
add("Paul");
add("George");
}};
Observable.just(names).subscribeOn(Schedulers.io())
.flatMap(new Func1<List<String>, Observable<String>>() {
#Override
public Observable<String> call(final List<String> names) {
return Observable.create(new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
for (String name : names) {
subscriber.onNext(name);
}
}
});
}
})
.map(new Func1<String, String>() {
#Override
public String call(String s) {
//Simulate expensive operation
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return s.toUpperCase();
}
}).subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
Log.v("RXExample", s + " on " + Thread.currentThread().getName());
}
});
For completion, applying the change recommended in the answer looks like the following and works nicely!
final List<String> names = new ArrayList<String>() {{
add("Ringo");
add("John");
add("Paul");
add("George");
}};
Observable.just(names).subscribeOn(Schedulers.io())
.flatMap(new Func1<List<String>, Observable<String>>() {
#Override
public Observable<String> call(final List<String> names) {
return Observable.create(new Observable.OnSubscribe<String>() {
#Override
public void call(final Subscriber<? super String> subscriber) {
for (final String name : names) {
Observable
.just(name)
.subscribeOn(Schedulers.from(Executors.newFixedThreadPool(5)))
.map(new Func1<String, String>() {
#Override
public String call(String s) {
//Simulate expensive operation
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return s.toUpperCase();
}
}).subscribe(new Observer<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
subscriber.onNext(name);
}
});
}
}
});
}
})
.subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
Log.v("RXExample", s + " on " + Thread.currentThread().getName());
}
});
you can parallelise work with flatMap as in the following example. I am using RxJava2 for testing.
For further explanation please read the flatMap usage from here: http://tomstechnicalblog.blogspot.de/2015/11/rxjava-achieving-parallelization.html
#Test
public void name() throws Exception {
final List<String> names = new ArrayList<String>() {{
add("Ringo");
add("John");
add("Paul");
add("George");
}};
Observable<String> stringObservable = Observable.fromIterable(names)
.flatMap(s -> {
return longWork(s).doOnNext(s1 -> {
printCurrentThread(s1);
}).subscribeOn(Schedulers.newThread());
});
TestObserver<String> test = stringObservable.test();
test.awaitDone(2_000, TimeUnit.MILLISECONDS).assertValueCount(4);
}
private Observable<String> longWork(String s) throws InterruptedException {
return Observable.fromCallable(() -> {
Thread.sleep(1_000);
return s;
});
}
private void printCurrentThread(String additional) {
System.out.println(additional + "_" + Thread.currentThread());
}
Related
I need to get a Coroutine Flow in my Java app. I try to test with RxJava but it's dosn't work for me
Single<Object> collect = Flowable.just(mContextServer.observeAllMessages()).collect(new Collector<Flow<Message>, Object, Object>() {
#Override
public Supplier<Object> supplier() {
Log.d(TAG, "supplier");
return null;
}
#Override
public BiConsumer<Object, Flow<Message>> accumulator() {
Log.d(TAG, "accumulator");
return null;
}
#Override
public BinaryOperator<Object> combiner() {
Log.d(TAG, "combiner");
return null;
}
#Override
public Function<Object, Object> finisher() {
Log.d(TAG, "finisher");
return null;
}
#Override
public Set<Characteristics> characteristics() {
Log.d(TAG, "characteristics");
return null;
}
});
someone would have a solution ?
I'm confused. I not found any articles about that.
Check my example, in this case longOperation will work on Schedulers.io()
private Completable longOperation() throws InterruptedException {
Thread.sleep(5000);
return Completable.complete();
}
private void doSomething() throws InterruptedException {
CompositeDisposable compositeDisposable = new CompositeDisposable();
compositeDisposable.add(Completable.defer(() -> longOperation())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableCompletableObserver() {
#Override
public void onComplete() {
customToast("long operation done");
}
#Override
public void onError(Throwable e) {
}
}));
}
but if I will remove Completable.defer(() -> longOperation()
private void doSomething() throws InterruptedException {
CompositeDisposable compositeDisposable = new CompositeDisposable();
compositeDisposable.add(longOperation()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableCompletableObserver() {
#Override
public void onComplete() {
customToast("long operation done");
}
#Override
public void onError(Throwable e) {
}
}));
}
I don't know where.
On which thread my method 'longOperation' will work ? I ask because my UI is freezed after invoke doSomething without Completable.defer.
I am new in rxJava.
Well, I was testing few examples to integrate operators in rxJava.
So, I have a problem with this:
Observable.just("JUAN", "LUCILA", "ARMANDO").map(new Function<String, Integer>() {
#Override
public Integer apply(String s) throws Exception {
return s.length();
}
}).all(new Predicate<Integer>() {
#Override
public boolean test(Integer integer) throws Exception {
return integer > 0;
}
}).filter(new Predicate<Boolean>() {
#Override
public boolean test(Boolean aBoolean) throws Exception {
return aBoolean;
}
}).subscribe(new Observer<Boolean>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Boolean value) {
Log.d("STATUS: ", "OK");
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
Log.d("STATUS: ", "COMPLETE");
}
})
So, AndroidStudio marks me error on subscribe(new Observer).
My objective is transform the names to a number by the length, so with all I hope make a condition, obviously it will be true, and late, filter that TRUE, from filter, and next show me a log message saying OK!
I hope that you can help me!
Thanks!
Check Single at http://reactivex.io/RxJava/2.x/javadoc/
As said in the comment Observable.all(...) you have type Single then from Single.filter(...) you have type Maybe.
So use you need toObservable() and then subscribe.
#CheckReturnValue
#SchedulerSupport(SchedulerSupport.NONE)
public final Maybe<T> filter(Predicate<? super T> predicate) {
ObjectHelper.requireNonNull(predicate, "predicate is null");
return RxJavaPlugins.onAssembly(new MaybeFilterSingle<T>(this, predicate));
}
`
Change to
Observable.just("JUAN", "LUCILA", "ARMANDO").map(new Function<String, Integer>() {
#Override
public Integer apply(String s) throws Exception {
return s.length();
}
}).all(new Predicate<Integer>() {
#Override
public boolean test(Integer integer) throws Exception {
return integer > 0;
}
}).filter(new Predicate<Boolean>() {
#Override
public boolean test(Boolean aBoolean) throws Exception {
return aBoolean;
}
}).toObservable().subscribe(new Observer<Boolean>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Boolean value) {
Log.d("STATUS: ", "OK");
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
Log.d("STATUS: ", "COMPLETE");
}
});
I'm trying to explore Rxjava 2 and get some issue with fetching information from website. Actutally Observer give me an error.
My code:
observable.subscribe(getObserver());
Observable
Observable<String> observable = Observable.fromCallable(new Callable<String>() {
#Override
public String call() throws Exception {
String data = getHeadlines(SOURCE_WEB);
return data;
}
});
Observer
protected <String> Observer<String> getObserver() {
return new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
Log.i("Observer get: ", "mamy sub");
Toast.makeText(context, "Wait...", Toast.LENGTH_SHORT).show();
}
#Override
public void onNext(String value) {
Log.i("Observer get: ",value.toString());
}
#Override
public void onError(Throwable e) {
Log.i("Observer get ", "Error");
}
#Override
public void onComplete() {
Log.i("Observer ", "complete");
}
};
}
My fetching method
public String getHeadlines(String source) throws IOException {
Document doc = (Document) Jsoup.connect(source).get();
Elements newsHeadlines = doc.select("h2");
return newsHeadlines.toString();
}
When I'm using AsyncTask everything work fine...
I am facing with the problem. As far as I know zip method from RxJava waits for all observables to complete.
But am I getting another behaviour.
Here is my code snippet
private PublishSubject<Void> firstSubject;
private PublishSubject<Void> secondSubject;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();
mDrawerHeaderView.postDelayed(new Runnable() {
#Override
public void run() {
// getSecondSubject().onNext(null);
}
}, 1000);
mDrawerHeaderView.postDelayed(new Runnable() {
#Override
public void run() {
getFirstSubject().onCompleted();
}
}, 1000);
}
protected PublishSubject<Void> createFirstSubject() {
firstSubject = PublishSubject.create();
return firstSubject;
}
protected PublishSubject<Void> createSecondSubject() {
secondSubject = PublishSubject.create();
return secondSubject;
}
protected PublishSubject<Void> getFirstSubject() {
return firstSubject;
}
protected PublishSubject<Void> getSecondSubject() {
return secondSubject;
}
private void loadData() {
Observable<Void> firstSubject = createFirstSubject();
Observable<Void> secondSubject = createSecondSubject();
Observable<Boolean> allDataTask = Observable.zip(firstSubject, secondSubject, new Func2<Void, Void, Boolean>() {
#Override
public Boolean call(Void aVoid, Void aVoid2) {
return true;
}
});
allDataTask
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Boolean>() {
#Override
public void onCompleted() {
Notifications.showSuccessMessage(getApplicationContext(), "COMPLETE");
}
#Override
public void onError(Throwable e) {
Notifications.showErrorMessage(getApplicationContext(), "ERROR");
}
#Override
public void onNext(Boolean aBoolean) {
Notifications.showSuccessMessage(getApplicationContext(), "NEXT");
}
});
}
In this case I got COMPLETE message, but I was expecting to get nothing because the second subject is not completed.
What I am doing wrong ?
Please help me to get desired behaviour.
Yes, it works as expected. It makes perfect sense to receive the onCompleted() here, because if one stream is done, as long as all the elements it emitted are "zipped", there's no way to "zip" anything more, so it's "completed". You can also play with the sequence here.