I have defined and interface, with an endpoint that returns JSON. Retrofit converts this JSON into MyObject. It could be also a list, map, etc, it doesn't matter now.
This is how I subscribe.
subscription = Retrofit.create(MyApi.class)
.doSomething()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<MyObject>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(MyObject myObject) {
}
});
My question is:
Is it possible that onNext is called more than once?
If yes, in which occasion?
In your case, no it's impossible, of course if you do not emit more items in doSomething() method.
But there is another, quite usual cases, for instance, if you use Local first approach and subscribing on hot observable which will emit new item each time when data in data base has change.
E.g. using retrofit:
#Override
public Observable<List<FollowMeUser>> getFollowMeUsers() {
return realm.where(FollowMeUser.class)
.findAll()
.asObservable()
.filter(RealmResults::isLoaded);
}
getFollowMeUsers()
.subscribe(users -> {Timber.d("saved data has changed")}, Timber::e);
Each time when you will insert/modify/delete FollowMeUser collection, all subscribers of getFollowMeUsers will be notified.
If your retrofit returns an array/list of data, onNext is called multiple times.
But if your retrofit returns a single data objext, onNext will be called only once.
Example:
//POJO
class User {
int userId;
String UserName;
}
//POJO
class UserData {
List<User> users;
}
interface RetrofitGithub {
#GET("...")
Observable<List<User>> getUsers();
#GET("...")
Observable<UserData> getUserData();
}
If you subscribe to getUsers() onNext will be called multiple N times.(N = size of the list)
If you subscribe to getUserData() onNext will be called only once.
Related
i'm working on project where i have to insert and delete data from room db , so basically i was using the old approach which is to implement Asynctask for background operations but since it is no longer recommended , i decided to use Rxjava instead , i tried to implement it but i'm not getting any result so far , and this is a piece of code where it shows the insertion of data
Completable.fromAction(new Action() {
#SuppressLint("CheckResult")
#Override
public void run() throws Exception {
recordingDb.insertRecording(modelUidd);
}
}).subscribeOn(Schedulers.io());
}
And this is the deletion method
public void DeleteData(modelUidd modelUidd) {
Completable.fromAction(new Action() {
#Override
public void run() throws Exception {
recordingDb.delete(modelUidd);
}
}).subscribeOn(Schedulers.io());
}
So basically i tried to use completable with the operator fromaction , i'm not sure if what i implemented is correct or not , any help would appreciated guys , thank you
The problem is that you are actually not subscribing to the observables, so nothing is happening.
To subscribe to an observable, you have to call the .subscribe() method.
I suggest that your methods defined in your DAO classes (or you "repository" classes), such as DeleteData in your example, return the Observable. Then, you can call the method in the DAO to get the Observable and subscribe to it from (ideally) a ViewModel or, if not, directly from an Activity. The moment you call the subscribe you will trigger the actual insertion or deletion, and will get a response from the onSuccess or onError defined callbacks.
For example:
public class MyViewModel extends ViewModel {
private MyRepository myRepository;
private final CompositeDisposable disposables;
#Inject
public MyViewModel(MyRepository myRepository) {
...
this.myRepository = myRepository;
disposables = new CompositeDisposable();
...
}
public void callObservableInRepository() {
disposables.add(myRepository.myObservable()
.subscribe(onSuccess -> {...} , onError -> {...}));
}
#Override
protected void onCleared() {
disposables.clear();
}
}
You can also check these two other answers for more information:
About async operations in RxJava
Using CompositeDisposable in ViewModel
What are the correct concepts and working of observables and observers in RxJava. I get confused by the words literal meaning. Whenever I change the values of observables its corresponding observers is not getting invoked i.e. I will explain this situation a bit more deeply, initially when I assign an observable with a list of strings(List list) and subscribe it to an observer, observer works perfectly but after that ,when I change the values of list(for example adding more String values to list) ...the observer's on next should automatically be invoked right.. but it isn't. Trying to implement in Android natively . I will be happy for some helps.
Observables work with three methods from Observer: onNext, onError and onCompleted. When you make Observable from a list and you subscribe it Observable will emit those values using onNext method and when it's finished it will call onCompleted method.
You can't change values that Observable is emitting by changing list you gave to some Observable operator. What would be you desired behaviour. Should Observable emit all elements on list change or should it emit only new changes.
This observable will emit all changes to collection made trough setCollection method:
public class CollectionObservable<T> extends Observable<T> {
private Collection<T> collection;
private List<Observer<? super T>> observers;
public CollectionObservable(Collection<T> collection) {
if (collection != null) {
this.collection = collection;
}
this.observers = new ArrayList<>(2);
}
public Collection<T> getCollection() {
return collection;
}
public void setCollection(Collection<T> collection) {
this.collection = collection;
emitValuesToAllObserver();
}
public void complete() {
if (this.collection != null) {
for (Observer<? super T> observer : this.observers) {
observer.onComplete();
}
}
}
#Override
protected void subscribeActual(Observer<? super T> observer) {
this.observers.add(observer);
emitValues(observer);
}
private void emitValuesToAllObserver() {
for (Observer<? super T> observer : this.observers) {
emitValues(observer);
}
}
private void emitValues(Observer<? super T> observer) {
if (this.collection != null) {
for (T obj : this.collection) {
observer.onNext(obj);
}
}
}
}
Note that in order to finish you manually have to call complete method.
Current code
Observable.from(listMovie)//list of movie
.flatMap(new Func1<Movie, Observable<FavMovieRes>>() {
#Override
public Observable<FavMovieRes> call(Movie movie) {
return moviesAPI.makeMovieFav(userId),
sessionId, new MakeMovieFav("movie", movie.getId(), movie.isFavList()));
}
})
.subscribe(new Subscriber<FavMovieRes>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(FavMovieRes favMovieRes) {
}
});
In above code I am passing Movie object list to the Observable and perform an operation on each movie instance in list when result gets from the API I want to change some database regarding that movie instance how can I get each Movie instance in OnNext() as well as onError method of subscribe method.
what I want is
Observable.from(listMovie)
.flatMap(new Func1<Movie, Observable<FavMovieRes>>() {
#Override
public Observable<FavMovieRes> call(Movie movie) {
return moviesAPI.makeMovieFav(String.valueOf(SharedPreferenceDataManager.getUserId(SyncFavListPeriodicTask.this)), SharedPreferenceDataManager.getSessionId(SyncFavListPeriodicTask.this), new MakeMovieFav("movie", movie.getId(), movie.isFavList()));
}
}).subscribe(new Subscriber<FavMovieRes>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e,Movie movie) {//or MakeMovieFav makeMovieFav
}
#Override
public void onNext(FavMovieRes favMovieRes,Movie movie) {//or MakeMovieFav makeMovieFav
}
});
I guess you have a List and want to process each received item for another single async operation. For this case you can flatmap each result.
flatMapIterable means that it will split each item in the list as Observable to the next Operation in your Stream. flatMap means that it will do an operation on the value received.
If you want to put the results back together you can use toList after flatMap.
You need to create an Observable (Operation) for your flatmap.
Kotlin:
Observable.just(data)
.flatMapIterable { it }
.flatMap{ moviesAPI.makeMovieFavObservable(whatEver) }
.subscribe( ... , ... , ... )
Java (Untested)
Observable.just(data)
//parse each item in the list and return it as observable
.flatMapIterable(d -> d)
// use each item and to another observable operation
.flatMap(data -> Observable.just(moviesAPI.movieStuff(data)))
// use each result and put it back into a list
.toList() // put the result back to a list
// subscribe it and log the result with Tag data, throw the error and output when completed
.subscribe( data -> Log.d("Data", "Data received "+ data),
error -> error.printStackTrace(),
() -> Log.d("Completed", "Completed")
);
So from my view model I call my Observable in another class:
getAuthentication.kickoff()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<RxOkHttpResponse>() {
#Override
public final void onCompleted( ) {
getAlbums();
}
#Override
public final void onError(Throwable e) {
userMsgHandler.showToast(mParent,mParent.getString(R.string.error_cannot_authenticate));
}
#Override
public final void onNext(RxOkHttpResponse response) {
mSubscription = response.subscription;
}
});
So this call obviously returns an Observable. So I'm wondering what the cleanest way to call subscriber.unsubscribe() on this Observable that is returned or if there even is a way (Right now I return it in onNext -- but I'm not happy bout that)
So is there a way to format the code to store .subscribe() in a member variable:
.observeOn(AndroidSchedulers.mainThread())
mSubscriber = .subscribe(new Subscriber<RxOkHttpResponse>() {
...
I'm using v 1.1.0
The answer depends on whether you're using RxJava 1 or 2. In case of RxJava 1 subscribe() will return Subscription instance which you can then call unsubscribe() on. However for RxJava 2 I believe you need to add onSubscribe()
This is the syntax I was looking for:
mSubscriber = ( getAuthentication.kickoff()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
).subscribe(new Subscriber<RxOkHttpResponse>() {
...
Now I can easily store mSubscriber in my view model for clean up triggered by OnDestroy() in my Activity
I've found nice example of usage RxJava at this article:
Subscription subscription = Single.create(new Single.OnSubscribe() {
#Override
public void call(SingleSubscriber singleSubscriber) {
String value = longRunningOperation();
singleSubscriber.onSuccess(value);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1() {
#Override
public void call(String value) {
// onSuccess
Snackbar.make(rootView, value, Snackbar.LENGTH_LONG).show();
}
}, new Action1() {
#Override
public void call(Throwable throwable) {
// handle onError
}
});
But since I am using Retrofit I would like to create RetrofitService and use Single class to combine the result of two requests to backend into one dataset, as described:
When subscribing to a Single, there is only an onSuccess Action and an
onError action. The Single class has a different set of operators than
Observable, with several operators that allow for a mechanism of
converting a Single to an Observable. For example, using the
Single.mergeWith() operator, two or more Singles of the same type can
be merged together to create an Observable, emitting the results of
each Single to one Observable.
Is it possible to achieve this (and how)?
Yes, see Retrofit Adapters
Only worked with Retrofit2.0