如何检测Android中的用户不活动
用户启动我的应用程序并login。
select会话超时为5分钟。
在应用程序上执行一些操作 (全部在前台)
现在用户把Myapp带到后台,启动一些其他的应用程序。
—->倒计时器启动并在5分钟后注销用户
或者用户closures屏幕。
—->倒计时器启动并在5分钟后注销用户
即使应用程序位于前台,但用户长时间不与应用程序交互(例如6-7分钟),我也需要相同的行为。 假设屏幕始终处于开启状态。 我想检测用户不活动 (即使应用程序在前台没有与应用程序交互),并启动我的倒数计时器。
基于Fredrik Wallenius的回答,我提出了一个我觉得很简单的解决scheme。 这是所有活动都需要扩展的基本活动类。
public class MyBaseActivity extends Activity { public static final long DISCONNECT_TIMEOUT = 300000; // 5 min = 5 * 60 * 1000 ms private Handler disconnectHandler = new Handler(){ public void handleMessage(Message msg) { } }; private Runnable disconnectCallback = new Runnable() { @Override public void run() { // Perform any required operation on disconnect } }; public void resetDisconnectTimer(){ disconnectHandler.removeCallbacks(disconnectCallback); disconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT); } public void stopDisconnectTimer(){ disconnectHandler.removeCallbacks(disconnectCallback); } @Override public void onUserInteraction(){ resetDisconnectTimer(); } @Override public void onResume() { super.onResume(); resetDisconnectTimer(); } @Override public void onStop() { super.onStop(); stopDisconnectTimer(); } }
我不知道一种跟踪不活动的方式,但有一种方法可以跟踪用户活动。 每当用户与应用程序进行任何交互时,都可以在您的活动中捕获一个名为onUserInteraction()
的callbackonUserInteraction()
。 我会build议做这样的事情:
@Override public void onUserInteraction(){ MyTimerClass.getInstance().resetTimer(); }
如果你的应用程序包含几个活动,为什么不把这个方法放在一个抽象的超类(扩展Activity
),然后让所有的活动扩展它。
MyApplication extends Application { private int lastInteractionTime; private Boolean isScreenOff = false; public void onCreate() { super.onCreate(); // ...... startUserInactivityDetectThread(); // start the thread to detect inactivity new ScreenReceiver(); // creating receive SCREEN_OFF and SCREEN_ON broadcast msgs from the device. } public void startUserInactivityDetectThread() { new Thread(new Runnable() { @Override public void run() { while(true) { Thread.sleep(15000); // checks every 15sec for inactivity if(isScreenOff || getLastInteractionTime()> 120000 || !isInForeGrnd) { //...... means USER has been INACTIVE over a period of // and you do your stuff like log the user out } } } }).start(); } public long getLastInteractionTime() { return lastInteractionTime; } public long setLastInteractionTime(int lastInteractionTime) { this.lastInteractionTime = lastInteractionTime; } private class ScreenReceiver extends BroadcastReceiver { protected ScreenReceiver() { // register receiver that handles screen on and screen off logic IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); registerReceiver(this, filter); } @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { isScreenOff = true; } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { isScreenOff = false; } } } }
isInForeGrnd ===>这里没有显示逻辑,因为它超出了问题的范围
您可以使用下面的设备代码将锁唤醒到CPU,
if(isScreenOff || getLastInteractionTime()> 120000 || !isInForeGrnd) { //...... means USER has been INACTIVE over a period of // and you do your stuff like log the user out PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); boolean isScreenOn = pm.isScreenOn(); Log.e("screen on.................................", "" + isScreenOn); if (isScreenOn == false) { PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "MyLock"); wl.acquire(10000); PowerManager.WakeLock wl_cpu = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyCpuLock"); wl_cpu.acquire(10000); } }
@Override public void onUserInteraction() { super.onUserInteraction(); delayedIdle(IDLE_DELAY_MINUTES); } Handler _idleHandler = new Handler(); Runnable _idleRunnable = new Runnable() { @Override public void run() { //handle your IDLE state } }; private void delayedIdle(int delayMinutes) { _idleHandler.removeCallbacks(_idleRunnable); _idleHandler.postDelayed(_idleRunnable, (delayMinutes * 1000 * 60)); }
我想你应该用这个代码,这是5分钟的空闲会话超时: – >
Handler handler; Runnable r; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handler = new Handler(); r = new Runnable() { @Override public void run() { // TODO Auto-generated method stub Toast.makeText(MainActivity.this, "user is inactive from last 5 minutes",Toast.LENGTH_SHORT).show(); } }; startHandler(); } @Override public void onUserInteraction() { // TODO Auto-generated method stub super.onUserInteraction(); stopHandler();//stop first and then start startHandler(); } public void stopHandler() { handler.removeCallbacks(r); } public void startHandler() { handler.postDelayed(r, 5*60*1000); //for 5 minutes }
除了ACTION_SCREEN_OFF
和ACTION_USER_PRESENT
广播之外,操作系统级没有“用户不活动”的概念。 您将不得不在自己的应用程序中定义“不活动”。
在我的活动基类中,我创build了受保护的类:
protected class IdleTimer { private Boolean isTimerRunning; private IIdleCallback idleCallback; private int maxIdleTime; private Timer timer; public IdleTimer(int maxInactivityTime, IIdleCallback callback) { maxIdleTime = maxInactivityTime; idleCallback = callback; } /* * creates new timer with idleTimer params and schedules a task */ public void startIdleTimer() { timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { idleCallback.inactivityDetected(); } }, maxIdleTime); isTimerRunning = true; } /* * schedules new idle timer, call this to reset timer */ public void restartIdleTimer() { stopIdleTimer(); startIdleTimer(); } /* * stops idle timer, canceling all scheduled tasks in it */ public void stopIdleTimer() { timer.cancel(); isTimerRunning = false; } /* * check current state of timer * @return boolean isTimerRunning */ public boolean checkIsTimerRunning() { return isTimerRunning; } } protected interface IIdleCallback { public void inactivityDetected(); }
所以在onResume方法 – 你可以在你的callback中指定动作,你想用它做什么…
idleTimer = new IdleTimer(60000, new IIdleCallback() { @Override public void inactivityDetected() { ...your move... } }); idleTimer.startIdleTimer();
在我的search过程中,我发现了很多答案,但这是我得到的最好答案。 但是这个代码的局限性在于它只适用于不是整个应用程序的活动。 以此为参考。
myHandler = new Handler(); myRunnable = new Runnable() { @Override public void run() { //task to do if user is inactive } }; @Override public void onUserInteraction() { super.onUserInteraction(); myHandler.removeCallbacks(myRunnable); myHandler.postDelayed(myRunnable, /*time in milliseconds for user inactivity*/); }
例如你使用8000,任务将在用户不活动8秒后完成。
我认为这需要将计时器和最后的活动时间结合起来。
所以像这样:
-
在onCreate(Bundle savedInstanceState)启动一个计时器,说5分钟
-
在onUserInteraction()只是存储当前的时间
到目前为止很简单。
现在,当定时器popup如下所示:
- 以当前时间和减去存储的交互时间来获得timeDelta
- 如果timeDelta> = 5分钟,就完成了
- 如果timeDelta <5分钟再次启动定时器,但这次使用5分钟 – 存储的时间。 换句话说,最后一次互动是5分钟