需求描述
在开发金融类APP时,经常会有这样一种需求,超过时间限制未操作页面,需要页面回到密码登录页,一般是回到手密页,那我们如何实现这样一种需求呢?
方案设计
APP跑起来之后,我们一定会有一种类似Manager的角色,它是单例的且与APP生命周期相同的一直跑在内存中。它的作用是管理业务,串联业务流程,启动页面等。我们可以单独做一个TouchTimeoutManager作为计时器,每隔一秒检查时间是否超过了限定时间,若超过了限定时间向外回调。另一个业务管理器,例如登录管理器实现监听方法,并在监听方法中调用返回手密登录页面的方法。
详细设计
这里我们描述TouchTimeoutManager的详细功能设计:
1、需要维护一个上次操作时间lastUpdatedTime,每次进行检查时,用当前时间减去上次操作时间,就得出了多长时间还未操作的时间数值。并对外提供更新更新lastUpdatedTime的方法,我们可以在每个activity启动时和在activity中覆盖dispatchTouchEvent()在其中更新lastUpdatedTime
check方法:
private void check(){
//时间差值
long actualTimeout = System.currentTimeMillis() - lastUpdatedTime;
//差值大于时间限制向外回调
if(actualTimeout >= timeoutInMs)
notifyAllListeners();
}
向外提供更新lastUpdatedTime方法:
public synchronized void onUserAction(){
lastUpdatedTime = System.currentTimeMillis();
}
2、计时
这里我们需要有一个计时任务,每秒执行一次,我们可以选择TimerTask、handler.postDealy()、甚至线程来做。这里我们选择使用handler.postDealy()
private Runnable checkTask = new Runnable() {
@Override
public void run() {
//停止检查标识
if(checkingStopped)
return;
//检查是否超时
check();
//每隔一秒检查一次
handler.postDelayed(this, 1000);
}
};
check()方法我们在上边贴过,这里就不贴了
3、向外回调
这里我们应该可以想到,向外回调采用观察者模式,本地维护一个listener,当事件发生遍历Listener调用onXXX()方法,并对外提供注册listener方法
维护的本地队列
private HashSet<HDTouchEvtTimeoutListener> listeners = null;
HDTouchTimeoutListener
public interface HDTouchEvtTimeoutListener {
void touchTimeoutReached(Object tag, long timeoutInMs);
}
notifyAllListeners():
private void notifyAllListeners(){
//防止有listener处理回调的时候执行unregister动作造成迭代器失效
HashSet<HDTouchEvtTimeoutListener> cloneListeners = (HashSet<HDTouchEvtTimeoutListener>) listeners.clone();
for(HDTouchEvtTimeoutListener listener : cloneListeners){
listener.touchTimeoutReached(tag, timeoutInMs);
}
}
对外提供注册方法:
public synchronized void registerListener(HDTouchEvtTimeoutListener listener){
if(listeners.contains(listener))
return;
listeners.add(listener);
startChecking();
check(); //保证时效性
}
这里比较好理解,我们就不赘述了
同时,我们提供startChecking和stopChecking方法,外部可以调用启动或停止check
private void startChecking(){
checkingStopped = false;
handler.postDelayed(checkTask, 1000);
}
private void stopChecking(){
checkingStopped = true;
handler.removeCallbacks(checkTask);
}
完整代码就不贴了,相信大家理解思路后自己可以写出检查计时器