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.
Related
Think about this func1() is in another java class, you can reach it by callback. My problem is I want to wait the func1 result. How can I do that?
launch{
func1()
func2()
func3()
// I want to catch the data here, so it should wait here but because of using rxjava (another thread), I cannot control it.
// I know if I use new retrofit libs, I can use coroutines, but right now, I cannot change old ones.
//My problem is I want to wait the func1 result here. How can I do that?
}
suspend fun func2(){}
suspend fun func3(){}
//Another java class
public Single<MyData> func1(){
apiClient.getMyData()
.subscribe(myData -> {
// Let's say this takes 5 seconds to get the data
}, throwable -> {
});
}
Add the library
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$coroutine_version"
Then call,
func1().await()
Read more here
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)
I would like to call getNote in background.
After I get result which is a Note object and still in background I would like to take two Note's values - text_encrypted and date.
After all I would like to return them to next step and in main thread set values on two textViews.
How could I achive this? Here is my code below.
Observable.fromCallable(() -> NotesDataBase.getNote(id))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(notes -> {
new Object[]{
GeneratorAES.decrypt(notes.text_encrypted),
CalendarUtils.showArticleTime(notes.date)
};
})
.subscribe(objects -> {
((TextView) findViewById(R.id.text2)).setText(objects[0]);
((TextView) findViewById(R.id.text1)).setText(objects[1]);
});
I assume I am doing something wrong in first flatMap but I am not sure.
This should not compile since flatMap() requires you to return an observable from your lambda. Additionally observeOn() will change the thread for all following operations of the chain.
Instead you have to call observeOn() after your operations and only map() the values. To make it nicer, you could also use Pair instead of Object[]:
Observable.fromCallable(() -> NotesDataBase.getNote(id))
.subscribeOn(Schedulers.io())
.map(notes -> Pair.create(
GeneratorAES.decrypt(notes.text_encrypted),
CalendarUtils.showArticleTime(notes.date)))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(pair -> {
((TextView) findViewById(R.id.text2)).setText(pair.first());
((TextView) findViewById(R.id.text1)).setText(pair.second());
});
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"))
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/