Hi I am quite naive with rxJava, so please let me know if my understanding is correct. As per my understanding if I use backpressure strategy with LATEST flag, I should be getting the most recent value. So I have a list, I am using flowable with subscriber, but it is still printing all values in onNext . Also please let me know how to test this backpressure strategy as I do not have real time data.
Following is my code
Observable.just(listObj).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).
flatMap(new Function<List<String>, Observable<String>>() {
#Override
public Observable<String> apply(List<String> ints) {
return Observable.fromIterable(ints);
}
}).toFlowable(BackpressureStrategy.LATEST).subscribe(new Subscriber<String>() {
#Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
#Override
public void onNext(String s) {
Log.d("Value", s);
}
#Override
public void onError(Throwable t) {
}
#Override
public void onComplete() {
}
});
}
///////////
Following is s simple method which creates arraylist
private ArrayList<String> createListForReturn() {
try {
if (listObj != null) {
listObj.add("Thanks");
listObj.add("fine");
listObj.add("working");
listObj.add("is");
listObj.add("Flowable");
listObj.add("Now");
listObj.add("Flowable");
listObj.add("For");
listObj.add("Programme");
listObj.add("RxJava");
listObj.add("Second");
listObj.add("My");
listObj.add("is");
listObj.add("This");
listObj.add(" ");
}
return listObj;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Related
I'm still new toRxJava and I am a bit confused on some code I have, where I don't have direct access to Observables, but pass an Observer as a parameter of some method to execute an Observable.
I would like to combine two Observers in some way but can't figure out how to do it with Observers.
Here I want to "combine" the mGetPotatoes and mGetBurger to show the potatoes and burger only when both do onNext (would be zip() for Observables I guess).
Show me some code
mGetPotatoes.execute( new DisposableObserver<List<Potatoes>>() {
#Override
public void onNext(List<Potatoes> potatoes) {
getMvpView().showPotatoes(mPotatoesMapper.mapPotatoesToViewModels(potatoes));
}
#Override
public void onComplete() {
}
#Override
public void onError(Throwable e) {
getMvpView().hideProgress();
getMvpView().showErrorMessage(e.getMessage());
}
});
mGetBurger.execute( new DisposableObserver<Burger>() {
#Override
public void onNext(Burger burger) {
getMvpView().showBurger(mBurgerMapper.mapBurgerToViewModel(burger));
}
#Override
public void onComplete() {
}
#Override
public void onError(Throwable e) {
getMvpView().hideProgress();
getMvpView().showErrorMessage(e.getMessage());
}
});
Edit
This question is a subset of this one where the template code for the mGetPotatoes and mGetBurger (that are UseCases) is.
I would sugegst you to change your architecture so theObservable is returned and you can manipulate it (change the scheduler, perform some actions, etc)
In case that option is not feasible you may get a workaround with Subjects. A Subject is an Observer which is also an Observable.
For your case:
Create a couple of PublishSubject
Combine both (with the zip) operator and subscribe to the result
Pass both subjects to your original use cases
Not sure about what framework this is, but you can turn back the execute calls into Observables by wrapping them:
Observable<List<Potatoes>> obs = new Observable<List<Potatoes>>() {
#Override public void subscribeActual(final Observer<? super List<Potatoes>> s) {
mGetPotatoes.execute(new DisposableObserver<List<Potatoes>>() {
#Override
public void onStart() {
s.onSubscribe(this);
}
#Override
public void onNext(List<Potatoes> potatoes) {
s.onNext(potatoes);
}
#Override
public void onComplete() {
s.onComplete();
}
#Override
public void onError(Throwable e) {
s.onError(e);
}
}
}
};
I have one case when I need to return an observable immediately, but then replace this observable with another one.
Here is an example
private Flowable<byte[]> mFlowableStream = Flowable.empty();
#Override
public Flowable<byte[]> startStreamRead() {
bindToService();
return mFlowableStream;
}
And then after binding to service I provide it a callback connection like that
#Override
public void bindToService() {
mAppContext.bindService(new Intent(mAppContext,StreamService.class), mServiceConnection, 0);
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
mServiceInterection = ((StreamServiceInterection.LocalBinder) binder).getServiceInteractor();
mStreamDisposable = mServiceInterection.getStream()
.subscribe(new Consumer<byte[]>() {
#Override
public void accept(byte[] data) throws Exception {
}
});
}
What I want to do is to somehow replace returned previously mFlowableStream with a new observable that I got from service.
What are possible strategies to implement this ? Maybe I should return some other value, like Future.
Please suggest how to solve this problem
Thanks
You can use Flowable.create instead of Flowable.empty
Then when new data come, just push to flowable.
Like Example
final ArrayList<FlowableEmitter<Integer>> arrEmitter = new ArrayList<>();
Flowable<Integer> futureFlow = Flowable.create(new FlowableOnSubscribe<Integer>() {
#Override
public void subscribe(final FlowableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
arrEmitter.add(e); // hold emitter to use later
}
}, BackpressureStrategy.BUFFER);
futureFlow.subscribe(new ResourceSubscriber<Integer>() {
#Override
public void onNext(Integer integer) {
System.out.println("onNext: " + integer);
}
#Override
public void onError(Throwable t) {
}
#Override
public void onComplete() {
System.out.println("onComplete");
}
});
// =========== When data come
FlowableEmitter<Integer> holdEmitter = arrEmitter.get(0);
holdEmitter.onNext(3);
Or use you can use **Subject* type according to your need
Understanding RxJava Subject — Publish, Replay, Behavior and Async Subject
I have started learning RxAndroid and below is the code I wrote to iterate over a model object (Results) that contains data fetched from the server. I'm iterating over the model object in the observable and providing a newly created object in the observer. I'm trying to take subscription of the observer to unsubscribe the task upon Orientation changes of the fragment. However the subscribe() returns VOID instead of subscription object.
Questions:
Does the latest version of RxAndroid handle unsubscription itself upon configuration/orientation change?
In case configuration change happens before the task is complete, the only way to restart this task that I can think of is, I persist the server response in onSavedInstance() and retrieve it from bundle when the fragment is recreated. It'll require booleans to figure out if the configuration change happened before the configuration change or not. Is there a graceful and cleaner way of coping with this?
private void createComicList(final List<Result> marvelResults) {
final MarvelComics marvelComics = new MarvelComics();
Observable marvelObservable2 = Observable.create(new ObservableOnSubscribe<MarvelComic>() {
#Override
public void subscribe(ObservableEmitter<MarvelComic> e) throws Exception {
for(Result result : marvelResults) {
MarvelComic marvelComic = new MarvelComic();
marvelComic.setDescription(result.getDescription());
marvelComic.setTitle(result.getTitle());
marvelComic.setPageCount(result.getPageCount());
marvelComic.setThumbnailUrl(result.getThumbnail().getPath());
marvelComic.setId(result.getId());
e.onNext(marvelComic);
}
e.onComplete();
}
});
marvelObservable2.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<MarvelComic>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(MarvelComic comic) {
marvelComics.getMarvelComicList().add(comic);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
showToast();
}
});
}
The Observable.subscribe(Observer<? super T>) method returns void in the 2.x since the Observer.onSubscribe(Disposable) is there to get the cancellation support that used to be Subscription in 1.x.
final CompositeDisposable composite = new CompositeDisposable();
Observable<Integer> source = Observable.just(1)
source.subscribe(new Observer<Integer>() {
#Override public void onSubscribe(Disposable d) {
composite.add(d); // <---------------------------------------------
}
#Override public void onNext(Integer t) {
System.out.println(t);
}
#Override public void onError(Throwable e) {
e.printStackTrace();
}
#Override public void onComplete() {
System.out.println("Done");
}
});
composite.add(source
.subscribeWith( // <-----------------------------------------------
new DisposableObserver<Integer>() {
#Override public void onNext(Integer t) {
System.out.println(t);
}
#Override public void onError(Throwable e) {
e.printStackTrace();
}
#Override public void onComplete() {
System.out.println("Done");
}
});
subscribe() method of Observable returns Subscription object in earlier versions of RxJava and current version returns an object of Disposble class which you can unsubscribe by invoking dispose() method.
For your second question you may check this answer Best practice: AsyncTask during orientation change
I receive data from network ,I implemented that part, but after receiving data from server in other thread, I want to save the data in Data base,which I want to implement not in main thread,so after receiving data where I should call the DB insertion method.Here is my code
Observable<List<PhotoAlbum>> searchResponseObservable =
mService.getAPI().getAlbums().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
searchResponseObservable.subscribe(new Observer<List<PhotoAlbum>>() {
#Override
public void onCompleted() {
Log.i("test","onComplete");
}
#Override
public void onError(Throwable e) {
Log.i("test","onComplete");
}
#Override
public void onNext(List<PhotoAlbum> photoAlbums) {
view().showSearchResult(photoAlbums);
}
});
You can use doOnNext() to insert received data into your DB like this:
Observable<List<PhotoAlbum>> searchResponseObservable = mService.getAPI()
.getAlbums()
.subscribeOn(Schedulers.newThread())
.doOnNext(photoAlbums -> insertIntoDb(photoAlbums))
.observeOn(AndroidSchedulers.mainThread());
searchResponseObservable.subscribe(new Observer<List<PhotoAlbum>>() {
#Override
public void onCompleted() {
Log.i("test","onComplete");
}
#Override
public void onError(Throwable e) {
Log.i("test","onComplete");
}
#Override
public void onNext(List<PhotoAlbum> photoAlbums) {
view().showSearchResult(photoAlbums);
}
});
Use flatMap to save in database and use Schedulers IO (Schedulers.io()) for background process
mService.getAPI().getAlbums().flatMap(new Func1<List<PhotoAlbum>, Observable<GetDriversResponse>>() {
#Override
public Observable<GetDriversResponse> call(GetDriversResponse mResponse) {
return mDatabaseHelper.setMyBus(mResponse);
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<GetDriversResponse>() {
#Override
public void call(List<PhotoAlbum> photoAlbums{view().showSearchResult(photoAlbums); }}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
throwable.printTrack
}
}));
i'm new in Rx programming (and I'm having a lot of fun so far ^^).
I'm trying to transform a AsyncTask call into an Rx function.
My function :
Get all the installed apps
normalize the labels
sort everything alphabetically
arrange them by group of letter (it was a Multimap(letter, list of apps)) and pass the result to an adapter to display everything.
Here is how I'm doing so far with Rx :
Observable.from(getInstalledApps(getActivity(), false))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<ResolvedActivityInfoWrapper, ResolvedActivityInfoWrapper>() {
#Override
public ResolvedActivityInfoWrapper call(ResolvedActivityInfoWrapper act) {
// Normalize labels
act.setLabel(Normalizer.normalize(act.getLabel(getPackageManager()).replace(String.valueOf((char) 160), "").trim(), Normalizer.Form.NFD).replaceAll("\\p{M}", ""));
return act;
}
})
.toList()
.subscribe(new Observer<List<ResolvedActivityInfoWrapper>>() {
List<ResolvedActivityInfoWrapper> list;
#Override
public void onCompleted() {
Observable.from(list).groupBy(new Func1<ResolvedActivityInfoWrapper, String>() {
#Override
public String call(ResolvedActivityInfoWrapper input) {
//Get groups by letter
String label = input.getLabel(getPackageManager());
if (!TextUtils.isEmpty(label)) {
String firstChar = label.substring(0, 1);
if (pattern.matcher(firstChar).matches()) {
return firstChar.toUpperCase();
}
}
return "#";
}
}).subscribe(this); // implementation below
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<ResolvedActivityInfoWrapper> list) {
Collections.sort(list, new Comparator<ActivityInfoWrapper>() {
#Override
// Sort all the apps in the list, not sure it's a good way to do it
public int compare(ActivityInfoWrapper info1, ActivityInfoWrapper info2) {
return info1.getLabel(getPackageManager()).compareToIgnoreCase(info2.getLabel(getPackageManager()));
}
});
this.list = list;
}
});
Once I groupedBy letters, on complete I subscribe with this :
#Override
public void onCompleted() {
//display the apps
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(GroupedObservable<String, ResolvedActivityInfoWrapper> input) {
//For each list of apps by letter i subscribe with an observer that will handle those apps (observer code below)
input.subscribe(new TestObserver(input.getKey()));
}
Observer :
private class TestObserver implements Observer<ResolvedActivityInfoWrapper> {
List<ResolvedActivityInfoWrapper> list;
String letter;
public TestObserver(String letter) {
list = new ArrayList<>();
this.letter = letter;
}
#Override
public void onCompleted() {
adapter.addData(letter, list);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(ResolvedActivityInfoWrapper input) {
list.add(input);
}
}
Everything works correctly excpets for one problem : the observer's onCompleted are called not in the right order. So I got all my apps, sorted by letter, but the groups are nots displayed in the right order (C first, then Y, then M etc ...).
I guess there are plenty of errors in the code, can you help me with this probleme and maybe understanding how all this works please ?
Thanks
UPDATE :
Following the advices in the commentary section (thanks people), here is what I'm trying after normalizing the labels :
Observable.from(list).groupBy(new Func1<ResolvedActivityInfoWrapper, String>() {
#Override
public String call(ResolvedActivityInfoWrapper input) {
String label = input.getLabel(getPackageManager());
if (!TextUtils.isEmpty(label)) {
String firstChar = label.substring(0, 1);
if (pattern.matcher(firstChar).matches()) {
return firstChar.toUpperCase();
}
}
return "#";
}
})
.toSortedList(new Func2<GroupedObservable<String, ResolvedActivityInfoWrapper>, GroupedObservable<String, ResolvedActivityInfoWrapper>, Integer>() {
#Override
public Integer call(GroupedObservable<String, ResolvedActivityInfoWrapper> obs1, GroupedObservable<String, ResolvedActivityInfoWrapper> obs2) {
return obs1.getKey().compareToIgnoreCase(obs2.getKey());
}
})
.subscribe(new Observer<List<GroupedObservable<String, ResolvedActivityInfoWrapper>>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<GroupedObservable<String, ResolvedActivityInfoWrapper>> input) {
String test = input.get(0).getKey();
}
});
But it never goes into the Compare function.