Convert Observable<List<T>> to List<T> - android

I want to get MutableLiveData<List<Country>>() object from Observable<List<Country>>, but I'm not able to find a way.
I'm using implementation below, but it's not working. Is there any other way to achieve it, or am I doing something wrong with my current implementation?
dataManagerAnonymous.countries.toList().blockingGet().single()
The above code shows NetworkOnMainThreadException and crashes the Application.

dataManagerAnonymous
.countires
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { result ->
// result is List<Country>
}
dataManagerAnonymous.countires probably perform network request, which should be done on background thread in order to prevent UI thread from blocking. subscribeOn(Schedulers.io()) invokes your request on background thread. observeOn(AndroidSchedulers.mainThread()) lets you to use result of this call on UI thread. Subscribe block will be called when your request had been completed successfully and result data is ready to process.

Related

RxJava2 wrapper for Firebase Firestore without switching threads?

I'm trying to create a reactive observable for Firebase Firestore calls.
I'm facing a threading issue. I'm using rxjava2 to handle threads and I don't want Firestore API to do that for me. It seems like Firestore calls are async, thus OnSuccess method is getting called on the main thread
Here is a simple example that showcases the issue:
Single<Integer> firestoreSingle = Single.create(emitter -> {
Log.d("TAG", Thread.currentThread().getName()); // -> RxCachedThreadScheduler-3 Thread
CollectionReference collectionRef = FirebaseFirestore.getInstance().collection("test_collection");
collectionRef.get().addOnSuccessListener(queryDocumentSnapshots -> {
Log.d("TAG",Thread.currentThread().getName()); // -> MAIN THREAD
List<DocumentSnapshot> documentSnapshotList = queryDocumentSnapshots.getDocuments();
emitter.onSuccess(documentSnapshotList.size());
}).addOnFailureListener(emitter::onError);
});
firestoreSingle
.subscribeOn(Schedulers.io())
.subscribe(howManyDocs -> {
Log.d("TAG",Thread.currentThread().getName()); // -> MAIN THREAD
Log.d("TAG","How many docs: " + howManyDocs);
});
Of course, I could add .observeOn(Schedulers.io()) to the reactive stream, but then I would not necessarily get the results on the same thread as the one I initially subscribed on.
I don't want the results neither in the main thread, nor in a different thread that the one I subscribed on.
Is there a way to query Firestore synchronously? How would you solve this issue?
You can use the answer that #MarkKeen suggested in the comment but for reference if you want to stick with RxJava, you can always call the method .blockingGet() to, as it suggests, block until a value is emitted.

How to perform n number of operations parallely in rxjava

I have a scenario. I am getting data from different sources in different time. I need to perform some intensive work on those data parallely on a background thread and get the result on the main thread. I thought of using BehaviorSubject. But I am not able to figure out how will I do the operation parallely and return the result back to main thread. Since subscribeOn doesn't have any effect in Subjects so I wont be able to perform the operation in background thread. Am I missing something to connect?
Can you try something like this pls:
Observable.merge(
Observable.just(1, 2, 3).subscribeOn(Schedulers.io()),
Observable.just("4", "5", "6").subscribeOn(Schedulers.io())
)
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
I recommend to take a look to ParallelFlowable and to try the example below
someFlowable
.parallel(NUMBER_OF_THREADS)
.runOn(scheduler)
.doOnNext(this::doSomeWork)
.sequential()
.subscribe{ result -> ... }

Room - Slow Query in Background

I'm currently implementing Room to replace my old SQL code, but I'm running into an issue where my query is very slow when running in the background.
For example, I have two identical queries, one that runs on the UI thread, and another that returns a Single. I'm using allowMainThreadQueries() to test this case.
#Query("SELECT * FROM event ORDER BY `begin` ASC LIMIT $LIMIT")
fun getUIThreadSchedule(): List<Event>
#Query("SELECT * FROM event ORDER BY `begin` ASC LIMIT $LIMIT")
fun getSchedule(): Single<List<Event>>
Now, when I run both of these and compare the time to give me a result, they are very different.
This will take ~6ms to complete.
val events = database.getUIThreadSchedule()
And this will take ~360ms to complete.
database.getSchedule()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
// elements are now here
}, {
// show an error view
})
I tried using other options, such as Flowable, but the result is the same.
Does anyone know what I could be doing wrong?
Thanks.
After a lot of looking into the issue, I found the why this call was taking longer than the blocking call.
When calling getSchedule(), the subscribe block is not run right when the query is completed. It has to wait for the UI thread, so if that's blocked in another aspect, it will have to wait.
// start query
database.getSchedule()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
// once ui thread is available, display content
}, {
// ...
})
The reason my UI thread was blocked is because I'm testing on cold start, so my Fragment would created, my query would be fired off, but then it would have to wait for the first frame of the rest of the UI to render before I could handle the getSchedule() result.
With the blocking call, it already had the UI thread, so there was no waiting.

Send multiple requests using RxJava

I am very new to using RxJava with Retrofit in Android. I have successfully written the API calls and developed the interface too. Now, I want to write my code in a way that I can send two requests: second request depending upon the values of first request. Can someone guide me if this is possible? If so then how? Any code snippet will really be helpful.
For example: following are two requests:
mCompositeDisposable.add(fcService.getStationList()
.subscribeOn(Schedulers.io()) // "work" on io thread
.observeOn(AndroidSchedulers.mainThread()) // "listen" on UIThread
.subscribe(this::handleResults, this::handleError)
);
mCompositeDisposable.add(fcService.getStationSensor("12345678")
.subscribeOn(Schedulers.io()) // "work" on io thread
.observeOn(AndroidSchedulers.mainThread()) // "listen" on UIThread
.subscribe(this::handleResults, this::handleError)
);
Second request is possible with the value from the first request's response. Is it possible to merge these two requests in a way that I write code only once for them?
With the flatMap operator you can check the response of the first call and choose the next action to follow, in this way you build a new Observable that you can subscribe to (The next "code" is kotlin style):
Single<StationSensor> newSingle =
fcService.getStationList().flatMap{ stationList ->
when(stationList){
"OK_value" -> fcService.getStationSensor(stationList)
else -> Single.error(RuntimeException("Error response"))
}
}

How to perform operations in different thread then notify main thread in rxandroid?

I pretty much understand the concept of subscribe (any code below subscribeOn will be performed in that particular thread) and observe (same with subscribeOn) in rxandroid/rxjava.
What I want to happen is to perform long io operation in background thread then notify the main thread if the operations is finished. To do that, I'm thinking of having a flatmap which is subscribed in Schedulers.io() then observe a subscribe in AndroidSchedulers.mainThread(), something like this:
Observable.just(1)
.subscribeOn(Schedulers.io())
.flatMap(o -> {
longIO();
return null;})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(//i want to notify user here);
This is actually performing the longIO() in a different thread, thus not blocking the main thread, my problem is, this doesn't notify the main thread that longIO() is finished, note that android doesn't allow notifying user by creating Toast or AlertDialog if not in main thread. The code doesn't seem to pass through subscribe
Note: I used just(1) even though I don't use the integer 1 because I want the method inside flatMap to be performed. If I used empty it won't go through flatMap
The return type of flatMap is Observable. If the flatMap returns a null Observable, the subscriber won't get notified. Change the return statement to return Observable.just(null);
But, it's preferred to use Observable.fromCallable() to wrap your longIO() method, so just(1) would be obsolete and code looks cleaner. Note: the return type offromCallable() isn't Observable, so the subscriber would get notified even null is returned. It would look like:
Observable.fromCallable(() -> {
longIO;
return null;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
I think that you are wrong in few things. IMO everything ABOVE subscribeOn() will be done in specific thread from thread pool. And of course everything BELOW observeOn should be pass into UI Thread.
Second thing - You cannot perform that your flatMap operator is returning null. You need to return Observable. If you don't need to pass data you can use : Observable.just(null) or Observable.never().
I think that better solution would be:
Observable.create(new Observable.OnSubscribe<Object>() {
#Override
public void call(final Subscriber<? super Object> subscriber) {
longIO();
}
})
.startWith(new Object()) //if you want to run it once
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();

Categories

Resources