I'm trying to use the Quickblox Android SDK combined with RxJava to make some chained and time-based Quickblox API calls. The API already have async methods. Here are two of them:
Create a session:
QBAuth.createSession(new QBEntityCallbackImpl<QBSession>() {
#Override
public void onSuccess(QBSession session, Bundle params) {
}
#Override
public void onError(List<String> errors) {
}
});
Create a Dialog (Chat Room)
QBChatService.getInstance().getGroupChatManager().createDialog(qbDialog,
new QBEntityCallbackImpl<QBDialog>() {
#Override
public void onSuccess(QBDialog dialog, Bundle args) {
}
#Override
public void onError(List<String> errors) {
}
});
As you saw, every API call must have a Callback Implementation as method parameter. The problem is that I have to make some chained API calls. Example:
Create empty session, then
Sign in, then
Retrieve user info, then
Login to chat service, then
....
I searched a little bit about RxJava and I saw that it's good to solve this kind of problem, because you can apply some filters and other things before make the next API call. The problem is that I don't know how to adapt this API to work with RxJava.
Should the API call with callbacks be inside the Observable call() method?
Should the onError() and the onSuccess() methods of the Quickblox API call the onError() and the onNext()/onCompleted() methods of the Subscriber?
Could anyone make some example of the use of
RxJava to create a session and then create a dialog using the
provided create session and create dialog API methods?
Here's a example of how to create observables using Observable.create() in your case:
Observable<QBSession> connectionObservable = Observable.create(new OnSubscribe<QBSession>() {
#Override
public void call(Subscriber<? super QBSession> subscriber) {
if (!subscriber.isUnsubscribed()) {
QBAuth.createSession(new QBEntityCallbackImpl<QBSession>() {
#Override
public void onSuccess(QBSession session, Bundle params) {
subscriber.onNext(session);
subscriber.onCompleted();
}
#Override
public void onError(List<String> errors) {
subscriber.onError(/*some throwable here*/);
}
});
}
}
});
Observable<QBDialog> dialogCreationObservable = Observable.create(new OnSubscribe<QBDialog>() {
#Override
public void call(Subscriber<? super QBDialog> subscriber) {
if (!subscriber.isUnsubscribed()) {
QBChatService.getInstance().getGroupChatManager().createDialog(qbDialog,
new QBEntityCallbackImpl<QBDialog>() {
#Override
public void onSuccess(QBDialog dialog, Bundle args) {
subscriber.onNext(dialog);
subscriber.onCompleted();
}
#Override
public void onError(List<String> errors) {
subscriber.onError(/*some throwable here*/);
}
});
}
}
});
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 2 streams, the first stream is a stream which takes data from database and call onCompleted() after finish taking data. The second stream is a stream that takes live data from server and never call onCompleted(). What I want to do is to create an operator that can do an action if the first stream(upstream) is an empty stream. Here is the sample:
getItemFromDatabase()
.lift(new DoIfEmptyOperator<Item>(new Action0() {
#Override
public void call() {
//Database is empty
System.out.println("Yeay successfully do an action");
}
}))
.concatWith(getItemFromServer()) // -----> intentionally never complete
.subscribe(new Subscriber<StoryItem>() {
#Override
public void onCompleted() {
//dosomething...
}
#Override
public void onError(Throwable e) {
//dosomething...
}
#Override
public void onNext(StoryItem storyItem) {
//dosomething
}
}));
Here is the code of DoIfEmptyOperator:
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
public class DoIfEmptyOperator<T> implements Observable.Operator<T,T>{
private Action0 action;
private boolean isEmpty = true;
public DoIfEmptyOperator(Action0 action) {
this.action = action;
}
#Override
public Subscriber<? super T> call(final Subscriber<? super T> childSubscriber) {
Subscriber<T> parentSubscriber = new Subscriber<T>() {
#Override
public void onCompleted() {
if(isEmpty) {
action.call();
}
childSubscriber.onCompleted();
}
#Override
public void onError(Throwable e) {
childSubscriber.onError(e);
}
#Override
public void onNext(T t) {
isEmpty = false;
childSubscriber.onNext(t);
}
};
childSubscriber.add(parentSubscriber);
return parentSubscriber;
}
}
However the action is never executed because the parentSubscriber onCompleted() is not firing, because the downstream never completed. If I remove
.concatWith(getItemFromServer())
then the action is executed. Any clue about how to solve the problem? I have dived to the source code of Observable.switchIfEmpty() but still have no clue about how it works.
I would advise against creating an operator.
This could be easily done with existing operators like this:
getItemFromDatabase()
.toList()
.flatMap(list -> {
if (list.isEmpty()) {
// side effect here
}
return getItemFromServer();
});
Have you thought about switchIfEmpty()? As an example of the usage of this operator - I have created some code on GitHub at the following link:
https://github.com/rs146/rxjava-simple/blob/master/src/test/java/SwitchIfEmpty.java
switchIfEmpty() is called when no items are emitted.
However, if you want to get items from the api or the db, then you can do something like the following:
Observable.concat(getFromDatabase(), getFromApi()).first();
As long as both getFromDatabase() and getFromApi() return the same Observable Type. This is a common Rx idiom in Android apps. It basically states that if an item's is not emitted from the database, then go fetch the result from the API instead.
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 have a fragment set up like so:
public mFragment extends Fragment implements Callback<mType> {
...
#Override
public void onViewCreated(View v, Bundle sis) {
Retrofit retrofit = new Retrofit.Builder().baseUrl("MYURL").addConverterFactory(GsonConverterFactory.create()).build();
api mAPI = retrofit.create(api.class);
Call<mType> call1 = mAPI.query1("query1"));
Call<mType> call2 = mAPI.query2("query2"));
call1.enqueue(this);
call2.enqueue(this);
}
#Override
public void onFailure(Throwable t) {
...
}
#Override
public void onResponse(final Response<mType> response, Retrofit retrofit) {
...
}
}
I need to make 2 api calls, which both return the same type. However, I want to handle both of them in different onResponse methods as I need to do distinct things to both of them. This is under Retrofit 2.0.
This is an API of a different service, so I do not have access to change any of the responses.
Is there a way to specify which method a Retrofit Call calls back to? I'm really hoping that this has as clean of a solution as if I were using two different return types. If worst comes to worst I can just duplicate the object and rename it but I think there is a "correct" way to do this.
queue your requests separately. So your response listeners will be separate for both the requests
call1.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response) {
}
#Override
public void onFailure(Throwable t) {
}
});
and
call2.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response) {
}
#Override
public void onFailure(Throwable t) {
}
});
I have to use a legacy library that using AsyncTask for a background job. How I can wrap an AsyncTask by an Observable object which I'm using on my current project.
The AsyncTask is encapsulated so I cannot access the synchronous call inside AsyncTask.
say you have an object asynchronousCall executing some async work with call() method which takes callback as a param, you can wrap it like that :
Observable.create(new Observable.OnSubscribe<Object>() {
#Override
public void call(final Subscriber<? super Object> subscriber) {
asynchronousCall.call(new CallBack() {
#Override
public void success(Object o) {
subscriber.onNext(o);
subscriber.onCompleted();
}
#Override
public void error(Throwable t) {
subscriber.onError(t);
}
});
}
});
Another approach to the case when you cannot or don't want to wrap execution in an Observable is to use Subjects:
public static void main(String[] args) {
Subject<Object, Object> subject = PublishSubject.create();
Listener listener = new Listener() {
#Override
public void onCallback(Object object) {
subject.onNext(object);
subject.onCompleted();
}
};
subject.subscribe(object -> yourReaction(object));
someMethodWithCallback(listener);
}
public interface Listener {
void onCallback(Object object);
}
Subject being an Observer allows you to send items into it, while it being an Observable allows you to subscribe to it and receive these events.