Execute code just before onComplete() in RxJava 2? - android

I need to close socket connection in my observable before RxLifecycle dispose it. How can I do that?

if you want to do an action after all, just before the subscriber unsubscribe from the observable you can use operator doOnUnsubscribe
#Test
public void testDoOnUnsubscribe() {
Integer[] numbers = {0, 1, 2, 3, 4};
Observable.from(numbers)
.doOnUnsubscribe(() -> System.out.println("Last action must be done here"))
.subscribe(number -> System.out.println("number:" + number),
System.out::println,
() -> System.out.println("End of pipeline"));
}
It should print in this order
number:0
number:1
number:2
number:3
number:4
End of pipeline
Last action must be done here

You could try using doFinally
Calls the specified action after this Observable signals onError or onCompleted or gets disposed by the downstream.
http://reactivex.io/RxJava/javadoc/io/reactivex/Observable.html#doFinally-io.reactivex.functions.Action-

one can try this too in case if you're iterating objects using filter and map for combining result.
.doOnTerminate(() -> Log.d(LOGGER, "terminated"))

Related

RxJava combine publishsubject with timeout

I want to be able to subscribe to publishsubject and wait for result, but no longer than 1 minute.
The problem is that if I do
publishsubject.timeout(1, TimeUnit.MINUTES).subscribe({result -> ... }, {error -> ... } )
I always get error even if before that I successfully get result. How to properly implement this approach?
You most likely get the timeout exception because timeout requires your source keeps producing items or completes within the specified time window. Thus, if you just signal one onNext to the PublishSubjectand never more, you'll get a timeout due to lack of a second onNext call.
So if you want one item, use take (before or after timeout):
publishsubject
.timeout(1, TimeUnit.MINUTES)
.take(1)
.subscribe(result -> { /* ... */ }, error -> { /* ... */ } )
In the exemple below I show how timeout works. For each emission, a new timeout is started and if a new item arrives before the timeout has ran the timeout is restated, otherwise an exception is thrown.
In the exemple, we can see 1, 2, 3 printing at console and it finish by a timeout exception because thE 4th item isn't here within the 200 milliseconds after the 3.
As I said in the comment below, you can avoid this if you know when you can terminate publishSubject. For exemple using take, takeUntil or calling publishSubject.onComplete() just after the 3rd item.
#Test
public void timeout() throws InterruptedException {
PublishSubject<Object> publishSubject = PublishSubject.create();
Observable<Object> timeout = publishSubject.timeout(200, TimeUnit.MILLISECONDS);
timeout
.subscribe(
e -> System.out.println(e),
error -> System.out.println("ERROR: " + error),
() -> System.out.println("complete")
);
sleep(50);
publishSubject.onNext(1);
sleep(150);
publishSubject.onNext(2);
sleep(199);
publishSubject.onNext(3);
sleep(201);
publishSubject.onNext(4);
Thread.sleep(2000);
}

RxJava PublishSubject+Debounce: the second item not emited

I want to use PublishSubject + debounce (in subscribe logic) for emit my items with delay. This is my code:
Subscription logic:
notificationSubject = PublishSubject.create<Notification>()
notificationSubject
.debounce(300, TimeUnit.MILLISECONDS)
.doOnIOSubscribeOnMain() // ext. fun, I hope you understand it
.subscribe {
displayNotification(it)
}
And emit objects logic:
showNotification(obj1)
showNotification(obj2)
// ...
fun showNotification(notification: Notification) {
notificationSubject.onNext(notification)
}
But on subscribe I receive only first emitted item (obj1). And if I emit two objects (obj3, obj4) again I receive only first of emitted item (obj3).
How to fix it?
Debounce is a lossy operator that skips items emitted too close to each other. You can't use that for addressing your requirements.
You could zip with an interval instead:
notificationSubject.zipWith(Observable.interval(300, TimeUnit.MILLISECONDS), (a, b) -> a)

How to chain observables with different intervals in RxJava?

I saw a whole lot of posts for having Rx delaying each emission of an event : How to make countdown timer with RxJS Observables?, How to use RxJava Interval Operator, Adding delay between Observable Items RxJava, RxJava delay for each item of list emitted, and others.
Though, I didn't see any for chaining with different delays.
Basically, I have a Textview and a list of letters, and I'd like to :
set the text to the first letter
wait 1500ms
set the text to null
wait 500ms
set the text to the second letter
wait 1500ms
set the text to null
wait 500ms
repeat for the entire list
A code implementation could maybe look somehow like this (but I guess doThing() is nonsense in Rx, and delay() is not meant for this) :
Observable.fromArray(new String[]{"A", "B", "C", "D", "E"})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.delay(500L, TimeUnit.MILLISECONDS)
.doThing((String i) -> {
textView.setText("");
Log.d("XXX", "MainActivity :: onCreate (110): letter="+ i);
})
.delay(1500L, TimeUnit.MILLISECONDS)
.doThing((String i) -> {
textView.setText(i);
Log.d("XXX", "MainActivity :: onCreate (110): letter="+ i);
});
How can I achieve this with Rx ?
EDIT : I could use the answer from rxjava delay: How to get variable delay on each item emitted from a list? with a list of letters where one letter on two is special (null maybe ?), but it seems overcomplicated.
Sequence: A (1500ms) null (500ms) B (1500ms) null (500ms) C (500ms) null (1500ms)
textAnimationDisposable = Observable.fromArray("A", "B", "C")
.concatMap(string ->
Observable.merge(
Observable.just(string),
Observable.just("").delay(1500, TimeUnit.MILLISECONDS)
)
.concatWith(Observable.<String>empty().delay(500, TimeUnit.MILLISECONDS))
)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.newThread())
.subscribe(string -> textView.setText(string));
The last solution you linked is quite useful for controlling the delay of each item separatly.

android : calling rxjava for a list of items

I have a list of items, for each item i wan to do an async job and then update the UI. I am using rxjav for doing async task. How can i loop through the list and do this. I tried with Observable.FromArray thought it didnt work
Observable.fromArray
flatMap is your answer. You will pass your list to Observable, in flatMap each item from the list will be passed so that you can do the async task. Finally, you can update the UI.
Observable.fromArray(yourArrayList)
.flatMap(item -> doAsyncTask)
.flatMap(item -> updateUI)
.subscribe();
You can refer to marble diagram on how flatMap works.
You'll need to use .flatMap() for this. Flatmap will allow you to perform an action and emit an observable for each item. You can use this to perform async operations on each item in the list. The flat map operation can return items of the same type or another type.
Example:
Suppose you have a list of items of type Object1. You want to upload these to a REST API. The API will return the uploaded object in the response.
// Create observable
Observable<Object1> uploadObjects = Observable.fromIterable(objectsToUpload)
.flatMap(object -> {
// Calls uploadObject on each item in the list
return MyAPI.uploadObject(object);
})
.subscribeOn(Schedulers.io()) // Performs the action on background thread
.observeOn(AndroidSchedulers.mainThread()); // Returns result on UI thread
// Subscribe to observable
Disposable subscription = uploadObjects
.subscribe(returnedObject -> {
// Called for each returned object
// Update UI here
}, throwable -> {
// Handle error here
}, () -> {
// Runs after all items completed
});
Suppose MyAPI.uploadObject() takes an Object1 as an argument but returns a different kind of object: type Object2. If this is the case, then the uploadObjects observable simply needs to be of type Observable<Object2>. Each returnedObject in the subscribe block with then be of type Object2.
Some nice examples from Dan Lew can be found here.

Observable seems to not call onNext after a while

I'm using RxAndroid library to process a list of items using subscriber / observable pattern.
My problem is that, when an item is processed, there is a progress bar that needs to be updated. But after processing 16 items, it seems that the observable is not calling onNext method until the rest of the items( 90) are processed and then calls 90 times onNext method. Why is this happening? can this be a memory issue?
Code below.
Subscriber:
public void startSingleRecognition(int id, int position) {
mAdapter.updateItemProgress(0, position);
Uri imageUri = Uri.parse(getHpCard(id).getUrlImage());
final int[] i = {0};
mSubscription = mRecognitionUtils
.getRecognitionObservable(imageUri, configurations)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
abbyResult -> mAdapter.updateItemProgress(++i[0], position),
e -> e.printStackTrace(),
() -> mAdapter.updateItemProgress(-1, position));
}
Observable:
public Observable<AbbyResult> getRecognitionObservable(Uri imageUri,
ArrayList<Configuration> configurations) {
return Observable.from(configurations)
.flatMap(
configuration -> Observable.just(recognize(imageUri, configuration, this)));
}
The method recognize does hard work processing images, my first thought was that this method is consuming a lot of memory and the observable cannot deliver the processed item to the subscriber until all method calls are done. But I'm not really sure, can anyone confirm this?
Thanks!
Well, I think I have solved it! The issue was using flatMap instead of concatMap. Here it is well explained: http://fernandocejas.com/2015/01/11/rxjava-observable-tranformation-concatmap-vs-flatmap/

Categories

Resources