What is the correct way to implement the tests below using rxjava2?
Given a list of ntp servers, test each one until you succeed.
Example:
time.nist.gov -> timeout
pool.ntp.org -> timeout
time.google.com -> success, get date
time.apple.com -> ignore
I do not want to test all in parallels but one by one. And if all fail, it restarts the test again.
Using only one server, the code I'm using is this:
public void getTime() {
timeObservable = Observable
.fromCallable(new Callable<Date>() {
#Override
public Date call() throws IOException {
return connectAndGetTime(HOST);
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(new Consumer<Throwable>() {
#Override
public void accept(Throwable error) {
Timber.tag(TAG).e(error);
}
})
.retry(5);
timeObservable.subscribe(new Consumer<Date>() {
#Override
public void accept(Date date) {
mDate = date;
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) {
Timber.tag(TAG).e(throwable);
}
});
}
Thanks!
Thanks Alexei, you're right.
Why complicate things?
The end result looks like this:
public void getTime() {
timeObservable = Observable
.fromCallable(new Callable<Date>() {
#Override
public Date call() {
for (String host : Arrays.asList("time.google.com", "time.apple.com", "time.nist.gov")) {
try {
return connectAndGetTime(host);
} catch (Exception e) {
Timber.tag(TAG).d("Sync (%s) fail!", host);
}
}
return null;
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(new Consumer<Throwable>() {
#Override
public void accept(Throwable error) {
Timber.tag(TAG).e(error);
}
})
.retry(5);
timeObservable.subscribe(new Consumer<Date>() {
#Override
public void accept(Date date) {
mDate = date;
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) {
Timber.tag(TAG).e(throwable);
}
});
}
Related
I am having an issue using RxJava on Android to read from async I/O. I create a Flowable and subscribe to an emitter. It works the first time, calling onNext and then onComplete when finished, but when I try the same operations again(create a new Flowable and subscribe), I get an UndeliverableException if I intentionally throw an I/O error. If I do an emitter.isCancelled, it returns true. Not sure why this happens.
Flowable getFlowable(){
Flowable.create(new FlowableOnSubscribe<Object>() {
#Override
public void subscribe(FlowableEmitter<Object> emitter) throws Exception {
getIOResponse(new IOListener() {
#Override
public void onInfo(Object ioResponse) {
emitter.onNext(ioResponse);
emitter.onComplete();
}
#Override
public void onError(Exception e) {
emitter.onError(e); //Throws UndeliverableException, emitter already cancelled
}
}
}
}
}
static void subscribe(){
disposable = getFlowable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.timeout(TIME_OUT_SECONDS, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
#Override
public void accept(Object myObject) throws Exception {
someListener.onSuccess(myObject);
}
}, throwable -> {
someListener.onError(throwable);
}, () -> {
Log.d("****", "Completed");
});
}
Android how to check the unit test with powermockito
public void updateProfile(final UserLogin updateUser) {
profileModelImple.updateUser(updateUser)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override
public void onCompleted () {
}
#Override
public void onError (Throwable e) {
Timber.e("authenticationModel -> login " + e);
EventBus.getDefault().post(null);
}
#Override
public void onNext (Object user) {
}
});
}
I'm using rx libraries im my app to call some REST api on my server and to show the results on screen.
I'm also following the MVP design pattern. So I have a Presenter and an Interactor classes.
In MainInteractor.java I have the following method:
public Observable<Card> fetchCard(final String clientId, final CardFetchedListener listener) {
Log.i(TAG, "FetchCard method");
// Manipulate the observer
return CARDS
.doOnCompleted(new Action0() {
#Override
public void call() {
Log.d(TAG, "CARDS Completed");
}
})
.flatMap(new Func1<Card, Observable<Card>>() {
#Override
public Observable<Card> call(final Card card) {
return ResourceClient.getInstance(card)
.getIDCard()
.observeOn(AndroidSchedulers.mainThread())
.doOnError(new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
Log.w(TAG, "interactor -> fetchCard 2", throwable);
}
}
})
.flatMap(new Func1<CardMeta, Observable<Card>>() {
#Override
public Observable<Card> call(CardMeta cardMeta) {
card.setCardMeta(cardMeta);
saveOrUpdateCardToTheDb(card);
return Observable.just(card);
}
})
.doOnCompleted(new Action0() {
#Override
public void call() {
Log.d(TAG, "Completed body");
}
});
}
});
}
In the logs I can see the "Completed Body" string.
The above method is being called by MainPresenter.java class as follows:
interactor.fetchCard(clientId, this)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Card>() {
#Override
public void onCompleted() {
Log.i(TAG, "fetchCard onCompleted");
view.hideProgressDialog();
view.updateCardsAdapter(cards);
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "Fetch Card error ", e);
onFailure(parseThrowable(e));
}
#Override
public void onNext(Card card) {
if (card != null) {
Log.i(TAG, card.getTenant() + " was fetched and will be displayed");
}
}
});
The problem is that the onCompleted method in the Presenter class is never bein called. I have tried to call onCompleted myself and it worked, but the problem is I don't know actually when the observable has finished emitting cards.
What am I doing wrong here?
UPDATE
CARDS is also an observable that contains meta info. It is initialized using
Observable.from(tenants)
.filter(...).flatMap(// I'm using create operator here and it is calling its onCompleted method successflly);
I'm new to rxjava 2 and i'm trying to execute someMethod in the background with a given interval and use the result on the UI thread. Can someone point me where i made mistake in my code or even better provide optimal code that does the job i need?
#Override
protected void onStop() {
subject.onNext(Long.valueOf(10005));
observable.unsubscribeOn(Schedulers.io());
super.onStop();
}
private void initAzimuthUpdater() {
subject = PublishSubject.create();
observable = Observable.interval(500, TimeUnit.MILLISECONDS)
.takeWhile(new Predicate<Long>() {
#Override
public boolean test(#NonNull Long aLong) throws Exception {
Log.d(TAG, "xxxxxxxxxxxx test: " + aLong);
return aLong != Long.valueOf(10005);
}
});
observable.flatMap(new Function<Long, ObservableSource<Float>>() {
#Override
public ObservableSource<Float> apply(#NonNull Long aLong) throws Exception {
return PublishSubject.create(new ObservableOnSubscribe<Float>() {
#Override
public void subscribe(#NonNull ObservableEmitter<Float> e) throws Exception {
e.onNext(someMethod());
}
});
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Float>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
Log.d(TAG, "xxxxxxxx onSubscribe:" + System.currentTimeMillis());
isRunning = true;
}
#Override
public void onNext(#NonNull Float o) {
Log.d(TAG, "xxxxxxxx onNext:" + System.currentTimeMillis());
//update UI
}
#Override
public void onError(#NonNull Throwable e) {
Log.d(TAG, "xxxxxxxx onError:" + System.currentTimeMillis());
}
#Override
public void onComplete() {
Log.d(TAG, "xxxxxxxx onComplete:" + System.currentTimeMillis());
}
});
subject.mergeWith(azimuthObservable);
}
You should use DisposableObserver and subscribeWith, save the Disposable into a CompositeDisposable, then call clear() on it from onStop(). The Observable operators return a new instance so ignoring their return value will have no effect on the original flow.
CompositeDisposable composite = new CompositeDisposable();
#Override
protected void onStop() {
composite.clear();
super.onStop();
}
private void initAzimuthUpdater() {
Disposable d = Observable.interval(500, TimeUnit.MILLISECONDS)
.flatMap(new Function<Long, ObservableSource<Float>>() {
#Override
public ObservableSource<Float> apply(#NonNull Long aLong)
throws Exception {
return Observable.create(new ObservableOnSubscribe<Float>() {
#Override
public void subscribe(#NonNull ObservableEmitter<Float> e)
throws Exception {
e.onNext(someMethod());
}
});
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<Float>() {
#Override
public void onStart() {
Log.d(TAG, "xxxxxxxx onSubscribe:" + System.currentTimeMillis());
isRunning = true;
}
#Override
public void onNext(#NonNull Float o) {
Log.d(TAG, "xxxxxxxx onNext:" + System.currentTimeMillis());
//update UI
}
#Override
public void onError(#NonNull Throwable e) {
Log.d(TAG, "xxxxxxxx onError:" + System.currentTimeMillis());
}
#Override
public void onComplete() {
Log.d(TAG, "xxxxxxxx onComplete:" + System.currentTimeMillis());
}
});
composite.add(d);
}
i am a newer on RxJava/RxAndroid. I want to use RxJava/RxAndroid to implement the following case: First, get data from network then do some checks on the data, if any of check fails, just show error in Main Thread.
you can see flow chart here!
I try some RxJava operations but fail to find a nice way to do so.
Can someone help me on this? Many thanks!
And I write some test code about this case (using String as data), is there any more simple way?
Observable.just(s)
.flatMap(new Function<String, ObservableSource<String>>() {
#Override
public ObservableSource<String> apply(final String s) throws Exception {
return Observable.create(new ObservableOnSubscribe<String>() {
#Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
if(s.length() < 3){
e.onError(new Throwable("len"));
}else{
e.onNext(s);
e.onComplete();
}
}
});
}
}).flatMap(new Function<String, ObservableSource<String>>() {
#Override
public ObservableSource<String> apply(final String s) throws Exception {
return Observable.create(new ObservableOnSubscribe<String>() {
#Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
if(s.startsWith("a")){
e.onError(new Throwable("start"));
}else{
e.onNext(s);
e.onComplete();
}
}
});
}
}).subscribeOn(AndroidSchedulers.mainThread())
.doOnError(new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
System.out.println("get error: " + throwable.getMessage());
}
}).subscribe(new Consumer<String>() {
#Override
public void accept(String s) throws Exception {
System.out.println(s);
}
});
While you can do it with flatMap() it is not needed here, you can simply use map() for checking the data and throwing errors:
Observable.just(s)
.map(new Function<String, String>() {
#Override
public String apply(#NonNull String s) throws Exception {
if (s.length() < 3) {
throw new Exception("len");
} else if (s.startsWith("a")) {
throw new Exception("start");
}
return s;
}
}
)
.subscribe(new Consumer<String>() {
#Override
public void accept(#NonNull String s) throws Exception {
System.out.println(s);
}
}, new Consumer<Throwable>() {
#Override
public void accept(#NonNull Throwable throwable) throws Exception {
System.out.println("get error: " + throwable.getMessage();
}
});
here you checking the value emitted and simply throw the appropriate Exception according to your checks.
Anyhow, in your example, you don't need to create by yourself an Observable for emitting errors/passing thru, you can use Observable.error() and Observable.just():
.flatMap(new Function<String, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(#NonNull String s) throws Exception {
if (s.length() < 3) {
return Observable.error(new Exception("len"));
} else if (s.startsWith("a")) {
return Observable.error(new Exception("start"));
} else {
return Observable.just(s);
}
}
})
moreover, your'e not handling onError() at your subscriber (but on doOnError()) so you'll crash with OnErrorNotImplementedException.
You can simplify your code a bit by eliminating Observable.create() (which you should not be using anyway):
Observable.just(s)
.flatMap(new Function<String, ObservableSource<String>>() {
#Override
public ObservableSource<String> apply(final String s) throws Exception {
return s.length() < 3 ? Observable.error(new Throwable("len"))
: Observable.just(s);
}
}).flatMap(new Function<String, ObservableSource<String>>() {
#Override
public ObservableSource<String> apply(final String s) throws Exception {
return s.startsWith("a") ? Observable.error(new Throwable("start"))
: Observable.just(s);
}
})
.subscribe(...)
Or you can use doOnEach and Guava Preconditions:
Observable.just(s)
.doOnEach(s -> {
Preconditions.checkArgument(s >= 3, "len");
Preconditions.checkArgument(!s.startsWith("a"), "start");
})
.subscribe(...)