I have an Observable which makes an emission every half second. When this Observable makes an emission, I do not care about the object which is emitted.
In this situation using a Completable is inadequate as a Completable can only make one zero argument emission.
This is what I am currently using, which works fine, but is imperfect
compositeDisposable.add(
Observable.interval(500L, TimeUnit.MILLISECONDS)
.timeInterval()
.observeOn(AndroidSchedulers.mainThread())
.flatMap(longTimed -> {
if (emissionBoolean) {
//todo: find an observable that can emit 0 arguments
return Observable.just(true);
}
return Observer::onComplete;
})
.subscribe(wishIWasAZeroArgumentBoolean -> {
onTick();
}));
this is what I want to have for my subscribe instead
.subscribe(() -> {
onTick();
}));
I think this is a valid question. Maybe cannot be used because Maybe does not emit more than once. _ can't be used as a parameter name in Java 9 or above.
There isn't a way you can send "empty" notifications. RxJava wiki suggests using Object in case you want to explicitly ignore the emitted value. For example:
compositeDisposable.add(
Observable.interval(500L, TimeUnit.MILLISECONDS)
.timeInterval()
.observeOn(AndroidSchedulers.mainThread())
.flatMap(longTimed -> {
if (emissionBoolean) {
//todo: find an observable that can emit 0 arguments
return Observable.just(new Object());
}
return Observable.empty()
})
.subscribe(object -> { // you still need to declare though.
onTick();
}));
Also, the code can be cleaner if you can switch to Kotlin, because in Kotlin you don't need to explicitly declare the name of the parameter if there is only one parameter.
compositeDisposable.add(
Observable.interval(500L, TimeUnit.MILLISECONDS)
.timeInterval()
.observeOn(AndroidSchedulers.mainThread())
.flatMap {
if (emissionBoolean) {
Observable.just(Any())
} else {
Observable.empty<Any>()
}}
.subscribe {
onTick()
}
Related
It's a simplified function.
It keeps returning 0 while I expect this to return 5. How come?
public int accessKey() {
a = 0;
mSubscription = mAccountManager.getLoginPassword()
.flatMap(loginPassword -> mServerAPI
.getProfilesList((new BaseRequest(
loginPassword.getLogin(),
loginPassword.getPassword(),
ClientGetter.getClientFromManager(),
CodeSnippets.getSha256(ClientGetter.getClientFromManager()))
)))
.doOnNext(profilesListe -> mProfilesList = profilesListe.getItems())
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<BaseResponse>() {
#Override
public void onCompleted() {
a =5;
}
return a; }
It's because of the asynchronous or non blocking behaviour , Normally during the scenarios of API calls fetching some data from database ,these behaviours we handle asynchronously,because otherwise your application will get stuck This post will help you to solve this matter. Refer this
you're executing an asynchronous operation here. your code doesn't execute "top down" here but will be executed on a different thread - Rxjava shifts this entire operation over to another thread and then returns the result to the thread specified, but this doesn't happen immediately. by the time your subscribe code has executed (we don't know when that will be) your return statement has already executed.
you could try change your code to something like this (just as an idea, i don't have any code similar to yours to create a working example):
return mAccountManager.getLoginPassword()
.flatMap(loginPassword -> mServerAPI
.getProfilesList((new BaseRequest(
loginPassword.getLogin(),
loginPassword.getPassword(),
ClientGetter.getClientFromManager(),
CodeSnippets.getSha256(ClientGetter.getClientFromManager()))
)))
.doOnNext(profilesListe -> mProfilesList = profilesListe.getItems())
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
this means that your method will now return an observable, which you can then subscribe on and subscribe to those changes where they are used.
this means that the signature of your method will have to change to support this new return type and the calling method will have to subscribe to this observable.
you describe your question as a simplified function, but I'll give you an even simpler (complete) example:
public Observable<Integer> foo() {
return Observable.just(5);
}
public void usage(){
Disposable disposable = foo().subscribeOn(something).observeOn(something).subscribe(
//inside this subscribe, like you'd normally do, you'd find the result of 5
)
...
//handle disposable
}
I used the Callback interface method and it worked! Many thanks
I have a list a want to refresh every minute.
For example the user list here : https://github.com/android10/Android-CleanArchitecture/blob/master/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserList.java
I add a periodical refresh using repeatWhen :
public Observable<List<User>> buildUseCaseObservable(Void unused) {
return this.userRepository
.users()
.repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(Observable<Object> objectObservable) throws Exception {
return objectObservable.delay(1, TimeUnit.MINUTES);
}
});
}
It works fine this way, calling onNext every minute.
But if I want to refresh immediately this list (because of user's action or because of a notification), I don't know how to perform that.
Should I cancel/dispose the observable and restart a new one ?
Thanks
From your code I understand that the users list is generated and emitted upon subscription.
Here are some solutions I can think of, instead of unsubscribing and resubscribing upon the event to which you want to react immediately:
Instead of using the repeatWhen operator, use the interval creation operator combined with the flatMap to invoke the subscription to a new Observable every minute and use the merge operator to add reaction to the other event in which you are interested. Something like this:
#Test
public void intervalObservableAndImmediateReaction() throws InterruptedException {
Observable<String> obs = Observable.interval(1, TimeUnit.SECONDS)
.cast(Object.class)
.mergeWith(
Observable.just("mockedUserClick")
.delay(500, TimeUnit.MILLISECONDS))
.flatMap(
timeOrClick -> Observable.just("Generated upon subscription")
);
obs.subscribe(System.out::println);
Thread.currentThread().sleep(3000); //to see the prints before ending the test
}
or adjusted to your needs (but the principal is the same):
Observable.interval(1, TimeUnit.MINUTES)
.mergeWith(RxView.clicks(buttonView))
.flatMap(timeOrClick -> this.userRepository.users());
You can use the flatMap operator as before, even while keeping you working current implementation and without merging to an interval - just keep your working code and in another area of the programme chain it to the RxBinding of your choosing:
RxView.touches(yourViewVariable)
.flatMatp(motionEvent -> this.userRepository.users())
.subscribe(theObserver);
Note that in this solution the subscription is done independently to the two observables. You'll probably be better off if you use different observers, or manage a subject or something on that line. A small test I ran showed one subscriber handled subscribing to 2 different observables with no problem (in Rxjava1 - didn't check in Rxjava2 yet), but it feels iffy to me.
If you aren't concerned with adjusting the refresh time after one of the other observables emits data you can do something like the following:
// Specific example of a user manually requesting
val request = Observable.create<String> { emitter ->
refresh.setOnClickListener {
emitter.onNext("Click Request")
}
}
.observeOn(Schedulers.io())
.flatMap {
userRepository.users()
}
// Refresh based off of your original work, could use something like interval as well
val interval = userRepository.users()
.subscribeOn(Schedulers.io())
.repeatWhen { objectObservable ->
objectObservable.delay(1, TimeUnit.MINUTES)
}
// Combine them so that both emissions are received you can even add on another source
Observable.merge(request,interval)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
contents.text = it.toString()
}, {
contents.text = it.toString()
},{
println(contents.text)
})
Then you don't have to dispose and resubscribe every time
I have following sample that demontrates the problem:
Observable<Integer> observable = Observable.create(subscriber -> {
IntStream.range(0, 1_00).forEach(subscriber::onNext);
subscriber.onCompleted();
}).doOnCompleted(() -> System.out.println("I'm first, but want to be second"));
observable.subscribe((i)-> {}, (e)-> System.err.println(e), ()-> System.out.println("I'm second, but want to be first"));
If I replace observable doOnCompleted with doAfterTerminate it works, but it has slightly different semantics.
How to achieve that subscriber onCompleted will be called before doOnCompleted on that observable ?
You should use doFinally()
This is the side effect method which will be called after onCompleted.
You can also refere this : https://stackoverflow.com/a/44922182/7409774
I'd like to re-subscribe to an observable using repeat(), but the condition that triggers the original observable is not met anymore when the first subscription is finished. How would I re-subscribe the observer in this case?
The code looks something like this:
RxInput.onInput(grid)
.flatMap(Grid::handle)
.flatMap(Grid::check)
.delay(300, TimeUnit.MILLISECONDS)
.flatMap(Grid::clean)
.repeat() // Does not work
.subscribe(g -> {System.out.println("Finished");});
The code of RxInput.onInput() is like this:
public static <T> Observable<T> onInput(T t) {
return Observable.create(subscriber -> {
if(InputSystem.isInputOn()) { // This is not true anymore when re-subscribing
subscriber.onNext(t);
}
});
}
Given that you seem to want to prevent emissions from initial subscription if isInputOn is false then define the observable like this:
Observable.defer(
() -> {
if (!InputSystem.isInputOn())
return Observable.empty();
else
return yourInput
.flatMap(Grid::handle)
.flatMap(Grid::check)
.delay(300, TimeUnit.MILLISECONDS)
.flatMap(Grid::clean)
.repeat();
})
.subscribe(...);
A quick extra note, do your damndest to avoid using Observable.create like in your example above. If you do emit things like that then you need to combine your observable with .onBackpressureXXX() because you may get a MissingBackpressureException from operators like flatMap downstream.
Here is an example:
return ApiClient.getPhotos()
.subscribeOn(Schedulers.io())
.map(new Func1<APIResponse<PhotosResponse>, List<Photo>>() {
#Override
public List<Photo> call(CruiselineAPIResponse<PhotosResponse> response) {
//convert the photo entities into Photo objects
List<ApiPhoto> photoEntities = response.getPhotos();
return Photo.getPhotosList(photoEntities);
}
})
.subscribeOn(Schedulers.computation())
Do I need both .subscribeOn(Schedulers.computation()) and .subscribeOn(Schedulers.computation()) because they are for different Observables?
No need for multiple subscribeOn calls; in this case, the second call is functionally a no-op but still holds onto some resources for the duration of the sequence. For example:
Observable.just(1)
.map(v -> Thread.currentThread())
.subscribeOn(Schedulers.io())
.subscribeOn(Schedulers.computation())
.toBlocking()
.subscribe(System.out::println)
Will print something like ... RxCachedThreadScheduler-2
You probably need observeOn(Schedulers.computation()) that moves the observation of each value (a List object in this case) to another thread.