emitting each item from list - android

I have a DAO method like this, which is working fine:
#Query("SELECT name FROM Weather")
Single<List<String>> getCity();
And a method in my activity:
mDatabase.getWeatherDao().getCity()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Function<List<String>, SingleSource<String>>() {
#Override
public SingleSource<String> apply(List<String> strings) throws Exception {
return ....;
}
})
.distinct()
next filter and so on.
How can I emit each item from List<String> strings in apply method, so that I can delete repeating (distinct()) items, filter and then use method toList()

You have to flatMap an Observable, like this:
.flatMapObservable(new Function<ArrayList<String>, ObservableSource<? extends String>>() {
#Override
public ObservableSource<? extends String> apply(ArrayList<String> source) throws Exception {
return Observable.fromIterable(source);
}
})
If you can use lambdas and method references you could replace all this ceremony with one of these:
// Lambda version
.flatMapObservable(source -> Observable.fromIterable(source))
// Method reference version
.flatMapObservable(Observable::fromIterable)

You could try something like this as well:
mDatabase.getWeatherDao().getCity()
.toObservable()
.flatMapIterable(r -> r)
.distinct()
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(..., ...)
This will work "as is" with strings, for more complex objects you'll need to make sure hashes and equals are working correct (of the entities inside the list).

Related

Best way to get List from Observable in Rxjava

I'm just exploring Rxjava in one of my android application, and got stuck at one place, honestly speaking I'm very new to this library so don't mind if my question frustrate someone;-)
So I'm trying to access the Room Database using RxJava where I'm returning the Observable List, once I get this Observable I'm trying to use map operator to get a list of ids & query again the database, which again returns me the Observable List but the map operator expects List as a return type. How can I tackle this please suggest?
Below is the code snippet:
private void getAllPcbs() {
isLoading.setValue(true);
getCompositeDisposable().add(
getRepositoryManager().loadAllPcbDetails()
.flatMap((Function<List<PcbDetails>, ObservableSource<?>>) pcbDetails -> {
List<Long> pcbList = new ArrayList<>();
for (PcbDetails details : pcbDetails)
pcbList.add(details.getPcbId());
return getRepositoryManager().loadAllPcbs(pcbList);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onSuccess, this::onError)
);
}
private void onError(Throwable throwable) {
isLoading.setValue(false);
}
private void onSuccess(Object o) {
isLoading.setValue(false);
pcbList.setValue((List<Pcb>) o);
}
public interface DbHelper {
Observable<List<PcbDetails>> loadAllPcbDetails();
Observable<List<Pcb>> loadAllPcbs(List<Long> pcbIdList);
}
Go like
getRepositoryManager().loadAllPcbDetails()
.flatMapIterable {
listPcbDetail-> listPcbDetail
// listPcbDetail is ArrayList<PcbDetails>
// Converts your list of ids into an Observable
// which emits every item in the list
}
.flatMap { pcbDetail ->
// pcbDetail is PcbDetails
getRepositoryManager().loadAllPcbs(pcbDetail.pcbIdList)
}.subscribe { listPcb ->
// listPcb is ArrayList<Pcb>
}

RxJava2 - Error returned by child Single is propagated despite handling in parent Single

So, I have a Repository class, which has a search() method which creates a zipped Single and returns data to a listener.
Inside of this method, I need to call 4 services and zip their results. The services return different data types, from which I build the SearchResult object.
The method looks like this:
fun search() {
Single.just(SearchResult.Builder())
.zipWith(
service1.search()
.subscribeOn(Schedulers.io())
.onErrorReturnItem(emptyList()),
{ result, data -> result.apply { this.data1 = data } })
.zipWith(
service2.search()
.subscribeOn(Schedulers.io())
.onErrorReturnItem(emptyList()),
{ result, data -> result.apply { this.data2 = data } })
// Other two services done in the same way
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ listener.onSearchComplete(it.build()) },
{ listener.onSearchFailed() })
}
The implementation of search() in the services looks like this:
fun search(): Single<List<DataTypeX>> =
Single.create<List<DataTypeX>> { subscriber ->
makeNetworkRequest()
?.let{
//logic omitted for clarity
subscriber.onSuccess(it)
} ?: subscriber.onError(IllegalStateException())
The problem is the last line. When this network call fails and the response is null, the IllegalStateException will be propagated and crash the app, instead of being silently caught by onErrorReturnItem(emptyList()).
Is there any reason for this? Am I misunderstanding the idea behind onErrorReturnItem()?

RxJava2 how call in parallel different request

I'm Really new on this but What I'm trying to do is
Do two call on parallel both are objects, then I need create a new object using the properties of both
This is a pseudo example that I need
OperatorINeed(service.callOne(), service.callTwo())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.concatMap(new BiFunction<ObjectA, ObjectB, ObjectC>() {
public ObjectC apply(ObjectA objectA, ObjectB objectB) {
// do things
return objectC;
}
})
onErrorResumeNext(...)
but I can't find any concrete example of this thing
use zip() operator, it will collect both emissions from the two service Observables that will run in parraell, and there you provide the BiFunction to map both Objects properties to a new single Object, afterwards you can apply concatMap() with objectC :
Observable.zip(service.callOne(), service.callTwo(),
new BiFunction<ObjectA, ObjectB, ObjectC>() {
#Override
public ObjectC apply(ObjectA objectA, ObjectB objectB) throws Exception {
// do things
return objectC;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.concatMap(objectC -> { //create an Observable using objectC})
.onErrorResumeNext(...)

Filter list of Object in Rxjava

I want to filter List<Object> based on query from user and then return List<Object> to him/her.I found out how to filter items But the problem is I don't know how return List<Object>. I also see some approach which iterate and call flatMap each time But I didn't think it's an elegant way.
This is my last attempt:
Observable.from(my_list_of_object)
.debounce(500, TimeUnit.MILLISECONDS)
.filter(new Func1<MyObject, Boolean>() {
#Override
public Boolean call(MyObject o) {
return o.getName().contains(query); //filtering
}
})
.observeOn(Schedulers.computation())
//problem is here and I dont know how
//to convert filtered Item to list
Just use toList() operator.
Check the documentation.
Observable.from(my_list_of_object)
.debounce(500, TimeUnit.MILLISECONDS)
.filter(new Func1<MyObject, Boolean>() {
#Override
public Boolean call(MyObject o) {
return o.getName().contains(query); //filtering
}
})
.toList()
.observeOn(Schedulers.computation())
You can find more extensive list of aggregate operators here.

Rxjava static generic utility method with transformer

Recently I saw an RxJavaarticle explaining Transformers and highlighting how they could be used to reuse Schedulers. I tried to use this and inside the same class, this method works fine:
<T>Observable.Transformer<T, T> applySchedulers() {
return new Observable.Transformer<T, T>() {
#Override
public Observable<T> call(Observable<T> observable) {
return observable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
I want to move this into a helper class with a static method so I can use it in my whole Androidapp. But when I try to use the method of this class
public class RxFunctions {
public static <T>Observable.Transformer<T, T> applySchedulers() {
return new Observable.Transformer<T, T>() {
#Override
public Observable<T> call(Observable<T> observable) {
return observable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
}
inside another class
public void requestLoginState() {
restClient.requestLoginState()
.compose(RxFunctions.applySchedulers())
.subscribe(new TimberErrorSubscriber<LoginStateResponse>() {
#Override
public void onCompleted() {
}
...
it will no longer recognise my Subscriber, error: Cannot resolve method 'subscribe(anonymous com.example.util.rx.TimberErrorSubscriber<com.example.network.retrofit.response.login.LoginStateResponse>)'
I'm using Java8without Retrolambda.
Changing the compose line to
.compose(this.<LoginStateResponse> RxFunctions.applySchedulers())
results in an error for the LoginState type saying Reference parameters are not allowed here
I'm fairly new to RxJava and grateful for any advice.
Edit: now Android does support java 8
You say you are using Java8 on android, but android does not support Java8 without plugins like retrolambda, so I'll asume that you are actually compiling with Java6 (since Java7 only works for KitKat and above).
In that scenario, you might need to make explicit the parametric type of your applySchedulers. I believe you tried to do that when you wrote this.<LoginStateResponse>, but that would only work if your generic method is inside your current class.
In your case what you actually need is to specify the type on the static method call:
.compose(RxFunctions.<LoginStateResponse>applySchedulers())

Categories

Resources