I want to set a count down timer inside each event in recyclerview.
I tried it inside onBindViewHolder. It is working but at the same time it is also affecting the UI.
For example, click events are not working.
Is the any best approach to resolve it?
You could use Observable.interval from RxJava
Here's a util function for countdowntimer
public static Observable<Long> countdownTimer(long countdownValue, Observer<Long> observer) {
if (observer == null) return Observable.just((long) 0);
//.interval is a cold observable
// it will emit separately for every observer
Observable<Long> timerObservale = Observable
.interval(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.takeWhile(new Predicate<Long>() {
#Override
public boolean test(Long aLong) throws Exception {
return aLong <= countdownValue;
}
})
.doOnError(Throwable::printStackTrace)
.observeOn(AndroidSchedulers.mainThread());
timerObservale.subscribe(observer);
return timerObservale;
}
Here's how you would use it
Utils.countdownTimer(60, new Observer<Long>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Long aLong) {
//do somethng
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onComplete() {
}
});
The utils function emits a long every second for a given period of time
I'm working on AndroidTv where I'm using the standard seekBar for playback.
This is how I'm using the RxSeekBar
RxSeekBar.changeEvents(seekBar)
.debounce(SEEKBAR_DEBOUNCE_TIME, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<SeekBarChangeEvent>() {
#Override
public void onSubscribe(Disposable disposable) {
compositeDisposable.add(disposable);
}
#Override
public void onNext(SeekBarChangeEvent seekBarChangeEvent) {
if (seekBarChangeEvent instanceof SeekBarProgressChangeEvent) {
if (seekBar.hasFocus()) {
DebugLog.d(TAG, "(PROGRESS) SeekBarProgressChangeEvent");
seekBarSeekProgress = seekBarChangeEvent.getView().getProgress();
onSeek();
}
}
}
#Override
public void onError(Throwable e) {
DebugLog.d(TAG, "RxSeek error - " + e.getMessage());
}
#Override
public void onComplete() {
}
});
Basically, I want to update things after the debounce timeout. This works fine 7/10 times but sometimes onNext is called prematurely and things go off hand.
Am I doing something wrong here?
I am new to reactive programming (RxJava and RxAndroid). I want to use RxView.clicks() instead of a click Listener. I put a Button into main layer and with Butterknife and in onCreate method Main activity I write this statement:
**//onCreate**
ButterKnife.bind(this);
RxView.clicks(btn_range)
.switchMap(new Function<Object, Observable<Integer>>() {
#Override
public Observable<Integer> apply(Object o) throws Exception {
return Observable.range(1,10);
}
})
.subscribe(new Observer<Integer>() {
#Override
public void onSubscribe(Disposable d) {
d.dispose();
}
#Override
public void onNext(Integer integer) {
Toast.makeText(MainActivity.this, integer+"", Toast.LENGTH_SHORT).show();
}
#Override
public void onError(Throwable e) {
Toast.makeText(MainActivity.this, e.getMessage()+"", Toast.LENGTH_SHORT).show();
}
#Override
public void onComplete() {
}
});
but when I run it, no toast appears.
I have converted my click listener to an observable and then I have changed the observable to a range of integer and finally I display it.
In your .subscribe() the Observer<Integer> calls d.dispose() as soon as it is subscribed.
So if your chain is disposed then it is not working anymore. The Disposable should be disposed when you no longer need the flow.
You could store the emitted Disposable and dispose it in the opposite lifecycle event callback to where you have subscribed it.
In the code below, the loadMoreStrings() method is have it's call() method execute before the getLabelsFromServer() completes. I'm still learning RxJava but I just can't get this to run properly.
private void fetchLabels() {
listObservable = Observable.fromCallable(new Callable<List<String>>() {
#Override
public List<String> call() {
return apiService.getLabelsFromServer();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
loadMoreStrings();
}
#Override
public void loadMoreStrings() {
stringListObservable.subscribe(new Action1<List<String>>() {
#Override
public void call(List<String> label) {
myStrings.addAll(label);
}
});
}
Because Observable type is lazy and it's not going to emit any items until you subscribe to it.
From code that you provided, you're not subscribing to listObservable. So it completes immediately and your loadMoreStrings() method is getting called.
I have the following code based on an example provided by #a.bertucci here Emit objects for drawing in the UI in a regular interval using RxJava on Android, where I zip an Observable with a Timer. When I trigger the subscription by calling processDelayedItems(), the code [A] in the zipped Observable is executed exactly once and one item is emitted to [B]. I would have expected code [A] to run continuously once triggered and keep emitting items every 1500 msec, but it obviously only runs once here.
private static void processDelayedItems() {
Observable.zip(
Observable.create(new Observable.OnSubscribe<Object>() {
#Override public void call(Subscriber<? super Object> subscriber) {
// [A] this code is only called once
subscriber.OnNext(o)
}
}),
Observable.timer(1500, 1500, TimeUnit.MILLISECONDS), new Func2<Object, Long, Object>() {
#Override public Object call(Object entity, Long aLong) {
return entity;
}
}
)
.subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Object>() {
#Override public void call(Object entity) {
// ... and accordingly one item is emitted [B]
}
}, new Action1<Throwable>() {
#Override public void call(Throwable throwable) {
throwable.printStackTrace();
}
}, new Action0() {
#Override public void call() {
}
});
}
Can anybody see the problem which I have here? Is it that I need to reference the Observable from outside the function to keep it alive for more time? Is it collected by GC (Android)? Is it a problem that the function is static?
What are the rules for Observables in terms of their livetime? Are there any best practices how longer-running Observables should be referenced and if they can be static at all? In my tests I noticed that it doesn't really matter, but maybe it does here, when a timer is involved.
--
Corrected code [not working yet]:
added repeat()
Observable.zip(
Observable.create(new Observable.OnSubscribe<Object>() {
#Override public void call(Subscriber<? super Object> subscriber) {
// [A] this code is only called once
subscriber.OnNext(o);
subscriber.OnCompleted();
}
}).repeat(Schedulers.newThread()),
Observable.timer(1500, 1500, TimeUnit.MILLISECONDS), new Func2<Object, Long, Object>() {
#Override public Object call(Object entity, Long aLong) {
return entity;
}
}
)
.subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Object>() {
#Override public void call(Object entity) {
// ... and accordingly one item is emitted [B]
}
}, new Action1<Throwable>() {
#Override public void call(Throwable throwable) {
throwable.printStackTrace();
}
}, new Action0() {
#Override public void call() {
}
});
You need repeat to generate an infinite Observable. E.g.,
Observable.create(new Observable.OnSubscribe<Object>() {
#Override public void call(Subscriber<? super Object> subscriber) {
// [A] this code is only called once
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(o);
}
if (!subscriber.isUnsubscribed()) {
subscriber.onCompleted();
}
}
}).repeat(Schedulers.newThread());
Is it that I need to reference the Observable from outside the function to keep it alive for more time? Is it collected by GC (Android)? Is it a problem that the function is static?
Since you use Schedulers.newThread() and timer, there will be some other Threads which has a reference to your Observable. You don't need more work.
What are the rules for Observables in terms of their livetime? Are there any best practices how longer-running Observables should be referenced and if they can be static at all? In my tests I noticed that it doesn't really matter, but maybe it does here, when a timer is involved.
You're right. It doesn't matter.
In regard to your comment, for simplicity you could do this,
Observable.timer(1500, 1500, TimeUnit.MILLISECONDS)
.flatMap(new Func1<Long, Observable<Object>>() {
#Override
public Observable<Object> call(Long aLong) {
String o = "0";
return Observable.from(o);
}
})
.subscribe(new Action1<Object>() {
#Override
public void call(Object aLong) {
System.out.println(aLong);
}
});
Here you still get the benefits of the timer without the added zip / repeat on top. It's still a bit verbose but it's a bit simpler.