问题
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:
BehaviorSubjectreceives and emitsUserInteractionobjects- 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()onObservableprovided bygetTimerExpiration()method. - We ignore all the emitted items, because we are waiting for the exception
- We are "transforming" exception to
UserInteraction.FINISHEDobject - 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