I can add a row using RxJava with the following,
Completable.fromAction(() -> db.userDao().insert(user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onComplete() {
}
#Override
public void onError(Throwable e) {
}
});
Dao:
#Insert(onConflict = OnConflictStrategy.REPLACE)
long insert(User user);
How can I get the row id after the DB operation?
If you want to use RxJava with Room you can change the insert function to return RxJava Single wrapping a Long, like:
#Insert
Single<Long> insert(User user);
This way you can just subscribe to this Single and you'll get the id as Long with something like this:
db.userDao().insert(user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<Long>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(Long aLong) {
// aLong is the id
}
#Override
public void onError(Throwable e) {
}
});
Related
I am new to RxJava and if I understand correctly the Observer is passed the Disposable on the onSubscribe so it can manually stop the processing if the dispose() has already been called.
I created the following code:
#NonNull Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new Observer<Long>() {
private Disposable d;
#Override
public void onSubscribe(#NonNull Disposable d) {
this.d = d;
}
#Override
public void onNext(#NonNull Long aLong) {
if(!d.isDisposed()) {
System.out.println("Number onNext = " + aLong);
}
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
System.out.println("completed");
}
});
but I can't figure out how to call dispose() for that subscription. subscribe with passing Observer as an argument returns void and subscribeWith does not accept my Observer without compile errors.
How is this supposed to work? What am I misunderstanding here?
The JavaDocs of Observable has a straightforward example:
Disposable d = Observable.just("Hello world!")
.delay(1, TimeUnit.SECONDS)
.subscribeWith(new DisposableObserver<String>() {
#Override public void onStart() {
System.out.println("Start!");
}
#Override public void onNext(String t) {
System.out.println(t);
}
#Override public void onError(Throwable t) {
t.printStackTrace();
}
#Override public void onComplete() {
System.out.println("Done!");
}
});
Thread.sleep(500);
// the sequence can now be disposed via dispose()
d.dispose();
Edit
The following examples are ways to get the Disposable out of the onSubscribe method but are generally not recommended:
// field in the owner class
Disposable disposable;
public void doReactive() {
Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new Observer<Long>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
disposable = d;
}
// ...
});
}
public void cleanup() {
if (disposable != null) {
disposable.dispose();
disposable = null;
}
}
or
SerialDisposable sd = new SerialDisposable();
Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new Observer<Long>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
sd.set(d);
}
// ...
});
// ...
sd.dispose();
You can use the DisposableObserver which can be easily disposed when you are done observing.
#NonNull Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new DisposableObserver<Long>() {
#Override
public void onNext(#NotNull Long aLong) {
//Do anything you want to do..
dispose();
}
#Override
public void onError(#NotNull Throwable e) {
//Handle the errors here..
dispose();
}
#Override
public void onComplete() {
dispose();
}
});
You can also use CompositeDisposable to dispose many observers at one time, For more details check this out.
https://www.tutorialspoint.com/rxjava/rxjava_compositedisposable.htm
This code was working before but after I update the code, it started showing
Cannot resolve method 'subscribe(anonymous io.reactivex.Observer<model.TwitterResponse>)'
Below is the sample code
public void callTwitterApi(final DisposableObserver observer, String URL, String twitterModel) {
RestClient.getInstance(mActivity).getService().callTwitter(URL,twitterModel)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<TwitterResponse>() {
#Override
public void onSubscribe(Disposable d) { }
#Override
public void onNext(TwitterResponse o) {observer.onNext(o); }
#Override
public void onError(Throwable e) { observer.onError(e); }
#Override
public void onComplete() { observer.onComplete();
}
});
}
I am using Retrofit for the network call in my android app. Now if the response if something wrong (maybe wrong data), I do not want the onComplete to be executed. Please see the code snippet,
restClient.getService().getProjectDetail(projectId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<List<Project>>() {
#Override
public void onNext(List<Project> value) {
/*Something wrong in the data and I would like to execute onError*/
}
#Override
public void onError(Throwable e) {
handleError(e, 0, "");
hideProgressDialog();
}
#Override
public void onComplete() {
hideProgressDialog();
}
});
Thanks in advance.
Since your end-consumer can crash, the straightforward way is to catch that exception and delegate to onError:
.subscribeWith(new DisposableObserver<List<Project>>() {
#Override
public void onNext(List<Project> value) {
try {
// something that can crash
} catch (Throwable ex) {
// tell the upstream we can't accept any more data
dispose();
// do the error handling
onError(ex);
}
}
#Override
public void onError(Throwable e) {
handleError(e, 0, "");
hideProgressDialog();
}
#Override
public void onComplete() {
hideProgressDialog();
}
});
On a side note, RxJava does pretty much this in its own operators when dealing with potentially failing user functions: try-catch, cancel the source and signal through onError.
You can use flatMap. ex:
restClient.getService().getProjectDetail(projectId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Function<Integer, Observable<List<Project>>>() {
#Override
public Observable<List<Project>> apply(List<Project> x) {
if(validate(x)){
return Observable.error(new Exception("Response is invalid"));
}else {
return Observable.just(x);
}
}
public boolean validate(List<Project> x){
return x.size()==0;
}
})
.subscribeWith(new DisposableObserver<List<Project>>() {
#Override
public void onNext(List<Project> value) {
/*Something wrong in the data and I would like to execute onError*/
}
#Override
public void onError(Throwable e) {
handleError(e, 0, "");
hideProgressDialog();
}
#Override
public void onComplete() {
hideProgressDialog();
}
});
example other:
Observable.just(1)
.flatMap(new Function<Integer, Observable<Integer>>() {
#Override
public Observable<Integer> apply(Integer x) {
if(validate(x)){
return Observable.error(new Exception("Response is invalid"));
}else {
return Observable.just(x);
}
}
public boolean validate(Integer x){
return x==1;
}
})
.subscribe(new Observer<Integer>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onComplete() {
}
#Override
public void onError(Throwable e) {
Log.e("ERROR", e.getMessage());
}
#Override
public void onNext(Integer integer) {
Log.d("flatMap", "onNext: " + integer.toString());
}
});
You are questioning the basic behaviour of rx-java. if you want call hideProgressDialog only once. you should delete that from onError. the sequence must destroy after problem.
but if you want to get other items in onNext and avoid onError you can use this method on your observable chain:onErrorResumeNext
restClient.getService().getProjectDetail(projectId).onErrorResumeNext(/*Func1*/)
consider this method will emit List<Project> in onNext instead of onError. and onComplete would not call
as long as you use retrofit the onNext only will invoke one times. so the better solution is the first one
I was using this code in Retrofit and Rx Java 1 to return an observable from a Retrofit call like this:
mCompositeSubscription.add(
ServiceFactory.createRetrofitService().setLike(mediaId,sessionMgr.getAuthToken())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<ResponseBody>() {
#Override
public final void onCompleted( ) {}
#Override
public final void onError(Throwable e) {
userMessageHandler.showDialog(mParentActivity,mParentActivity.getString(R.string.error_setting_data_title),
mParentActivity.getString(R.string.error_set_like_msg) + e.getMessage(),0);
}
#Override
public void onNext(ResponseBody response) { }
})
);
I can't figure out how to convert it to RX Java 2. I have come up with this but not sure it is right:
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<User>(){
#Override
public void onNext(User user) {
authMgr.setUser(user);
}
#Override
public void onError(Throwable t) {
mProgressDlg.dismiss();
alertDlg.showIt(mResources.getString(R.string.err_register),
t.getMessage(), "",
"", mParentActivity, JAlertDialog.POSITIVE,null);
}
#Override
public void onComplete() { }
});
You should be able to use the RxJava2 adapter in retrofit. This will allow you to have your Retrofit API return RxJava2 types.
Here's a solid example: https://medium.com/3xplore/handling-api-calls-using-retrofit-2-and-rxjava-2-1871c891b6ae
I came up with this but I'm still testing...
mCompositeDisposable.add( ServiceFactory.createRetrofitService().registerNewUser(BuildConfig.CLIENT_KEY, data.email,
data.fname, data.lname, data.birthday,data.city,
data.state, mAvatarUrl, coords, Long.toString(mSessionId) ,
data.pwd, layerMgr.getNonce() )
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<User>(){
#Override
public void onNext(User user) {
}
#Override
public void onError(Throwable t) {
mProgressDlg.dismiss();
alertDlg.showIt(mResources.getString(R.string.err_register),
t.getMessage(), "",
"", mParentActivity, JAlertDialog.POSITIVE,null);
}
#Override
public void onComplete() { }
}));
How can I bind two subscriptions like:
1) Retrofit&RX which converts JSON into list of strings shown in recyclerView.
restClient.getCatFacts()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<CatFactsResponse>() {
#Override
public void onCompleted() {
Log.i(TAG, "onCompleted");
}
#Override
public void onError(Throwable e) {
Log.i(TAG, "onError, " + e.getMessage());
}
#Override
public void onNext(CatFactsResponse catFactsResponse) {
catFactsList = catFactsResponse.getCatFacts();
}
});
2) And Jack Wharton's RxBinding library to react to changes made in EditText widget.
subscription = RxTextView
.textChangeEvents(editText)
.debounce(400, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.newThread())
.subscribe(new Observer<TextViewTextChangeEvent>() {
#Override
public void onCompleted() {
Log.i(TAG, "onCompleted");
}
#Override
public void onError(Throwable e) {
Log.i(TAG, "onError >> " + e.getMessage());
}
#Override
public void onNext(TextViewTextChangeEvent textViewTextChangeEvent) {
Log.i(TAG, textViewTextChangeEvent.text().toString());
}
});
to get list which is dynamically filtered using EditText. Am I supposed to use classes like Subject or sth? If yes, then how should it look like? Thanks for help :)
You should use flatMap operator
subscription = RxTextView
.textChangeEvents(editText)
.debounce(400, TimeUnit.MILLISECONDS)
.map(new Func1<TextViewTextChangeEvent, String>() {
#Override
public String call(TextViewTextChangeEvent textViewTextChangeEvent) {
return textViewTextChangeEvent.text();
}
})
.flatMap(new Func1<String, Observable<CatFactsResponse>>() {
#Override
public Observable<CatFactsResponse> call(String text) {
return restClient.getCatFacts(text)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
})
.subscribe(...);