问题
I'm working on a use-case where I have to implement a sort of screen timeout after the completion of which application navigates to the main screen. I want it to implemente it using Observable
and use Observable.timer()
or Observable.interval()
for the timing. (Either is suitable for my use-case.). Every time the user interacts with the activity I have to reset or refresh my timer Observable
.
This is where I am stuck. I don't know how to refresh or reset an Observable
. A simple way would be to dispose the previous one and create a new one each time in onUserInteraction()
, but I do not think that a good approach. What are the alternatives?
回答1:
Solution to this problem is not as simple as one might think. I have tried implement different approach. Instead of "clear or reset" observable, I'm using BehaviorSubject
what is both Observer
and Observable
.
public class RxTimerNavigation {
private final long TIMEOUT_INTERVAL = 4;
private final BehaviorSubject<UserInteraction> userInteractionsSubject = BehaviorSubject.create(UserInteraction.IGNORED); // (1)
public void onInteraction() {
userInteractionsSubject.onNext(UserInteraction.IGNORED); // (2)
}
public Observable<UserInteraction> getTimerExpiration() {
return userInteractionsSubject
.timeout(TIMEOUT_INTERVAL, TimeUnit.SECONDS) // (3)
.filter(__ -> false) // (4)
.onErrorReturn(__ -> UserInteraction.FINISHED) // (5)
.first() // (6)
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.asObservable();
}
static class UserInteraction {
static final UserInteraction IGNORED = new UserInteraction();
static final UserInteraction FINISHED = new UserInteraction();
}
}
Let's explain marked parts:
BehaviorSubject
receives and emitsUserInteraction
objects- Everytime user interacts with UI, you should call method
onInteraction()
and new item is "added" to Subject. - Sets Timeout. It throws
TimeoutException
, when there is no emitted item for specified amount of time (TIMEOUT_INTERVAL
). Timer is started when you callsubscribe()
onObservable
provided bygetTimerExpiration()
method. - We ignore all the emitted items, because we are waiting for the exception
- We are "transforming" exception to
UserInteraction.FINISHED
object - We want emit only one value, because we are finishing
回答2:
That's a perfectly valid approach. Dispose / unsubscribe the existing, obsolete timer and start a new observable with the now-correct values. If you have too many user interactions that may cause undue performance
The other way to do this is to have something like a volatile expected-blank
value that is updated every time the user interacts with the application. You start a timer that will trigger on that expected-blank
moment, and which checks whether that value is in the future. If it is, it starts a new instance of the timer and completes. If it is in the present/past, it blanks the screen and completes.
来源:https://stackoverflow.com/questions/44239862/observable-timer-for-screen-timeout-android