RxJava2 connectableObservables - autoConnect(2) - why is it not waiting for 2 subscribers to call connect? - rx-java2

I have created a connectedObservable like this:
final List<Integer> list = new ArrayList<Integer>();
for(int j=1;j<=3;j++)
list.add(j);
Observable<Integer> observable = Observable.fromIterable(list);
this observable emits 1, 2, 3
now i convert it into a connectableObservable this way :
observable.publish().autoConnect(2);
i am therefore expecting since i passed in 2 to autoConnect that it will not trigger until 2 subscribers have been found. but instead it is executing on only 1 subscriber found.
let me show you what i tried:
observable.subscribe(new Consumer<Integer>() {
#Override
public void accept(Integer integer) {
Log.v("consumer1:", ""+integer);
}
});
I am expecting that this DOES NOT print anything to the log. but instead i get the following:
consumer1:: 1
consumer1:: 2
consumer1:: 3
according to the documentation on autoConnect(int
numberOfSubscribers):
* #param numberOfSubscribers the number of subscribers to **await** before calling connect
* on the ConnectableObservable. A non-positive value indicates
* an immediate connection.

In RxJava, you should not ignore the returns of operators:
Observable<Integer> shared = observable.publish().autoConnect(2);
shared.subscribe(new Consumer<Integer>() {
#Override
public void accept(Integer integer) {
Log.v("consumer1:", ""+integer);
}
});
shared.subscribe(new Consumer<Integer>() {
#Override
public void accept(Integer integer) {
Log.v("consumer2:", ""+integer);
}
});
Recommended reading: https://github.com/ReactiveX/RxJava#simple-background-computation

Related

How to Iterate through list with RxJava and perform initial process on first item

I am new to RxJava and finding it very useful for network and database processing within my Android applications.
I have two use cases that I cannot implement completely in RxJava
Use Case 1
Clear down my target database table Table A
Fetch a list of database records from Table B that contain a key field
For each row retrieved from Table B, call a Remote API and persist all the returned data into Table A
The closest I have managed is this code
final AtomicInteger id = new AtomicInteger(0);
DatabaseController.deleteAll(TableA_DO.class);
DatabaseController.fetchTable_Bs()
.subscribeOn(Schedulers.io())
.toObservable()
.flatMapIterable(b -> b)
.flatMap(b_record -> NetworkController.getTable_A_data(b_record.getKey()))
.flatMap(network -> transformNetwork(id, network, NETWORK_B_MAPPER))
.doOnNext(DatabaseController::persistRealmObjects)
.doOnComplete(onComplete)
.doOnError(onError)
.doAfterTerminate(doAfterTerminate())
.doOnSubscribe(compositeDisposable::add)
.subscribe();
Use Case 2
Clear down my target database table Table X
Clear down my target database table Table Y
Fetch a list of database records from Table Z that contain a key field
For each row retrieved from Table B, call a Remote API and persist some of the returned data into Table X the remainder of the data should be persisted into table Y
I have not managed to create any code for use case 2.
I have a number of questions regarding the use of RxJava for these use cases.
Is it possible to achieve both my use cases in RxJava?
Is it "Best Practice" to combine all these steps into an Rx "Stream"
UPDATE
I ended up with this POC test code which seems to work...
I am not sure if its the optimum solution however My API calls return Single and my database operations return Completable so I feel like this is the best solution for me.
public class UseCaseOneA {
public static void main(final String[] args) {
login()
.andThen(UseCaseOneA.deleteDatabaseTableA())
.andThen(UseCaseOneA.deleteDatabaseTableB())
.andThen(manufactureRecords())
.flatMapIterable(x -> x)
.flatMapSingle(record -> NetworkController.callApi(record.getPrimaryKey()))
.flatMapSingle(z -> transform(z))
.flatMapCompletable(p -> UseCaseOneA.insertDatabaseTableA(p))
.doOnComplete(() -> System.out.println("ON COMPLETE"))
.doFinally(() -> System.out.println("ON FINALLY"))
.subscribe();
}
private static Single<List<PayloadDO>> transform(final List<RemotePayload> payloads) {
return Single.create(new SingleOnSubscribe<List<PayloadDO>>() {
#Override
public void subscribe(final SingleEmitter<List<PayloadDO>> emitter) throws Exception {
System.out.println("transform - " + payloads.size());
final List<PayloadDO> payloadDOs = new ArrayList<>();
for (final RemotePayload remotePayload : payloads) {
payloadDOs.add(new PayloadDO(remotePayload.getPayload()));
}
emitter.onSuccess(payloadDOs);
}
});
}
private static Observable<List<Record>> manufactureRecords() {
final List<Record> records = new ArrayList<>();
records.add(new Record("111-111-111"));
records.add(new Record("222-222-222"));
records.add(new Record("3333-3333-3333"));
records.add(new Record("44-444-44444-44-4"));
records.add(new Record("5555-55-55-5-55-5555-5555"));
return Observable.just(records);
}
private static Completable deleteDatabaseTableA() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
System.out.println("deleteDatabaseTableA");
emitter.onComplete();
}
});
}
private static Completable deleteDatabaseTableB() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
System.out.println("deleteDatabaseTableB");
emitter.onComplete();
}
});
}
private static Completable insertDatabaseTableA(final List<PayloadDO> payloadDOs) {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
System.out.println("insertDatabaseTableA - " + payloadDOs);
emitter.onComplete();
}
});
}
private static Completable login() {
return Completable.complete();
}
}
This code doesn't address all my use case requirements. Namely being able to transform the remote payload records into multiple Database record types and insert each type into its own specific target databased table.
I could just call the Remote API twice to get the same remote data items and transform first into one database type then secondly into the second database type, however that seems wasteful.
Is there an operand in RxJava where I can reuse the output from my API calls and transform them into another database type?
You have to index the items yourself in some manner, for example, via external counting:
Observable.defer(() -> {
AtomicInteger counter = new AtomicInteger();
return DatabaseController.fetchTable_Bs()
.subscribeOn(Schedulers.io())
.toObservable()
.flatMapIterable(b -> b)
.doOnNext(item -> {
if (counter.getAndIncrement() == 0) {
// this is the very first item
} else {
// these are the subsequent items
}
});
});
The defer is necessary to isolate the counter to the inner sequence so that repetition still works if necessary.

unable to add counter in Flink 1.3.2

I am trying to add a counter in Flink as mentioned here, but the issue is that counter.inc() is returning void instead of Integer. Code for my Metric is given as below
private static class myMetric extends RichMapFunction<String,Integer> {
private Counter counter ;
#Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
this.getRuntimeContext().
getMetricGroup().
counter("countit");
}
#Override
public Integer map(String s) throws Exception {
return this.counter.inc();
}
}
It should work better if you assign a value to your counter:
this.counter = getRuntimeContext()
.getMetricGroup()
.counter("countit");
You may find the documentation helpful.

How to preserve informations about original observable on RxJava2

I have a REST call returning a collection (the original), this collection is filtered but on the subscribe onSuccess I what to obtain both the original list and the filtered one.
I don't know how to 'pass' this second element, which operator should I use to obtain this result?
I show a simplified version of my code below
Observable.fromCallable(new Callable<List<Integer>>() {
#Override public List<Integer> call() throws Exception {
// dynamic list obtained from REST call
// for simplicity here I return a list
return Arrays.asList(1, 2, 3, 4);
}
})
.flatMap(new Function<List<Integer>, ObservableSource<Integer>>() {
#Override public ObservableSource<Integer> apply(List<Integer> integers) throws Exception {
return Observable.fromIterable(integers);
}
})
.filter(new Predicate<Integer>() {
#Override public boolean test(Integer integer) throws Exception {
return integer > 2;
}
})
.toList()
.subscribe(new SingleObserver<List<Integer>>() {
#Override public void onSubscribe(Disposable d) {}
#Override public void onSuccess(List<Integer> value) {
///////////////////
// here I want both original and filtered list
///////////////////
}
#Override public void onError(Throwable e) {}
});
One way is with ConnectableObservable. You need to share the emissions of your initial stream. Something like this
ConnectableObservable<List<Integer>> connectableObservable
= Observable.fromCallable(() -> {
// dynamic list obtained from REST call
// for simplicity here I return a list
return Arrays.asList(1, 2, 3, 4);
}).publish();
Single.zip(connectableObservable.flatMapIterable(integers -> integers)
.filter(integer -> integer > 2)
.toList(),
connectableObservable.elementAtOrError(0),
(integers, lists) -> combine(integers, lists))
.subscribe(o -> {
///////////////////
// here you ll have a new object containing both the initial list and the filtered list
///////////////////
});
connectableObservable.connect();

Android Mobile Apps query from the azure database returns last row only

There's more than 15 items in my azure database table called Events.
I've tried to run most of the commands found on
https://learn.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-android-how-to-use-client-library such as :
List<Events> results = eventsTable.execute().get()
and
List<Events> results = eventsTable.select("Events").execute().get();
and
List<Events> results = eventsTable.top(20).execute().get();
to return all the row items in the table. The queries seem to run on the last row of the table only and returns the last row or nothing at all when query is executed.
Though the ToDoItem Quickstart from Azure works perfectly with all the queries - which is odd.
Here's some of the code
ArrayList<Events> events = new ArrayLists<Events>();
private void EventsFromTable() {
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>(){
#Override
protected Void doInBackground(Void... params) {
try {
final List<Events> results = EventsTable.execute().get();
runOnUiThread(new Runnable() {
#Override
public void run() {
for (Events event : results) {
Events ev = new Events(event.getName(), event.getVenue(), event.getDate());
events.add(ev);
System.out.println("size is " +events.size());
<======This returns "size is 1"======>
}
}
});
} catch (final Exception e){
createAndShowDialogFromTask(e, "Error");
}
return null;
}
};
runAsyncTask(task);
}
Might any one know what the matter is?
Thanks
According to your code, the variable events seems to be a public shared instance of ArraryList in your Android app, so I don't know whether exists the case which multiple threads access it concurrently. The implementation of ArrayList class is not synchronized, please see here.
So please use the code below instead of the code ArrayList<Events> events = new ArrayLists<Events>(); when you shared the variable between UI thread and data async task thread.
List<Events> events = Collections.synchronizedList(new ArrayLists<Events>());
And I think it's better for copying data retrieved from table via addAll method, not add method for each, as the code below.
#Override
public void run() {
events.addAll(results);
}

Average in RxJava

I am trying to make a system resource monitor using Rx. I use a thread for observable which returns the CPU Usage every 1000 milliseconds. Now I want my subscriber to find the average of the CPU usage every 10 seconds.
public class seperate {
private ScheduledThreadPoolExecutor executorPool;
public void test()
{
Observable<Double> myObservable = Observable.create(
new Observable.OnSubscribe<Double>() {
#Override
public void call(Subscriber<? super Double> sub) {
executorPool = new ScheduledThreadPoolExecutor(9);
int timeout1 = 10;
TimerTask timeoutTimertask1=new MyTimerTasks(sub);
executorPool.scheduleAtFixedRate(timeoutTimertask1,timeout1, timeout1,
TimeUnit.MILLISECONDS);
// This returns the cpu usage every 10ms.
}
}
);
Subscriber<Double> mySubscriber = new Subscriber<Double>() {
#Override
public void onNext(Double s) { System.out.println(s); }
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) { }
};
myObservable.subscribe(mySubscriber);
}
}
You can use buffer or window to divide source emission into groups of items, then calculate average on each group.
Avarage is a part of rxjava-math library.
Moreover you can simplify your code using interval.
Below is example using window and interval:
Observable myObservable = Observable.interval(10, TimeUnit.MILLISECONDS)
.map(new Func1<Long, Double>() {
#Override
public Double call(Long aLong) {
Double d = 100.;//calculate CPU usage
return d;
}
})
.window(10, TimeUnit.SECONDS)
.flatMap(new Func1<Observable<Double>, Observable<Double>>() {
#Override
public Observable<Double> call(Observable<Double> windowObservable) {
return MathObservable.averageDouble(windowObservable);
}
});
Use MathObservable like so:
MathObservable.averageLong(longsObservable).subscribe(average -> Timber.d("average:%d", average));
More info can be found here:
https://github.com/ReactiveX/RxJava/wiki/Mathematical-and-Aggregate-Operators
Source Code:
https://github.com/ReactiveX/RxJavaMath