用户启动我的应用程序并登录。
选择会话超时时间为5分钟。
在应用程序上执行一些操作。(全部在前景中)
现在,用户将Myapp移到后台并启动其他应用程序。
----> 倒计时定时器开始,在5分钟后注销用户
或者用户关闭屏幕。
----> 倒计时定时器开始,在5分钟后注销用户
即使应用程序在前台但用户长时间不与应用程序交互,例如6-7分钟,我也希望具有相同的行为。假设屏幕一直开启。 我想检测到用户不活动(即使应用程序在前台也没有与其交互),并启动倒计时计时器。
用户启动我的应用程序并登录。
选择会话超时时间为5分钟。
在应用程序上执行一些操作。(全部在前景中)
现在,用户将Myapp移到后台并启动其他应用程序。
----> 倒计时定时器开始,在5分钟后注销用户
或者用户关闭屏幕。
----> 倒计时定时器开始,在5分钟后注销用户
即使应用程序在前台但用户长时间不与应用程序交互,例如6-7分钟,我也希望具有相同的行为。假设屏幕一直开启。 我想检测到用户不活动(即使应用程序在前台也没有与其交互),并启动倒计时计时器。
我根据Fredrik Wallenius的答案提出了一个我认为相当简单的解决方案。这是一个需要所有活动扩展的基础活动类。
public class MyBaseActivity extends Activity {
public static final long DISCONNECT_TIMEOUT = 300000; // 5 min = 5 * 60 * 1000 ms
private static Handler disconnectHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// todo
return true;
}
});
private static 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();
}
}
Activity
时创建多个Handler
和Runnable
实例。如果我们将这两个成员转换为“静态”的,就可以避免这种情况发生。另外,你能告诉我为什么在onStop()
中调用了stopDisconnectTimer()
吗? - Gaurav BhorIntent(CurrentActivity.this, MainActivity.class)
并且使用startActivity(intent)
启动它呢?因为在静态上下文中无法引用CurrentActivity.this
和startActivity()
。 - Tur1ng我不知道如何跟踪用户的不活动时间,但可以跟踪用户的活动。您可以在活动中捕获一个名为onUserInteraction()
的回调函数,该函数在用户与应用程序进行任何交互时都会被调用。我建议像这样做:
@Override
public void onUserInteraction(){
MyTimerClass.getInstance().resetTimer();
}
如果你的应用包含多个活动(Activity),为什么不将这个方法放在一个抽象的超类中(继承Activity
),然后让所有的活动都继承它呢。
MyTimerClass
的实现是什么? - McSullivan我认为你应该使用这段代码,它用于设置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
}
@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));
}
public class 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 void 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);
}
}
在操作系统层面上,没有“用户不活动”的概念,除了 ACTION_SCREEN_OFF
和 ACTION_USER_PRESENT
广播。您将需要在您自己的应用程序中定义“不活动”的某种方式。
在我的搜索中,我找到了许多答案,但这是我得到的最佳答案。但这段代码的限制是它仅适用于活动而不是整个应用程序。将其作为参考。
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*/);
}
Kotlin中处理用户交互超时的方法:
//Declare handler
private var timeoutHandler: Handler? = null
private var interactionTimeoutRunnable: Runnable? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_aspect_ratio)
//Initialise handler
timeoutHandler = Handler();
interactionTimeoutRunnable = Runnable {
// Handle Timeout stuffs here
}
//start countdown
startHandler()
}
// reset handler on user interaction
override fun onUserInteraction() {
super.onUserInteraction()
resetHandler()
}
//restart countdown
fun resetHandler() {
timeoutHandler?.removeCallbacks(interactionTimeoutRunnable);
timeoutHandler?.postDelayed(interactionTimeoutRunnable, 10*1000); //for 10 second
}
// start countdown
fun startHandler() {
timeoutHandler?.postDelayed(interactionTimeoutRunnable, 10*1000); //for 10 second
}
在Android中,可以使用onUserInteraction()
重写方法来检测用户的不活动状态。
@Override
public void onUserInteraction() {
super.onUserInteraction();
}
以下是示例代码,当用户不活动时,在3分钟后退出(从HomeActivity -> LoginActivity)
public class HomeActivity extends AppCompatActivity {
private static String TAG = "HomeActivity";
private Handler handler;
private Runnable r;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
handler = new Handler();
r = new Runnable() {
@Override
public void run() {
Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
startActivity(intent);
Log.d(TAG, "Logged out after 3 minutes on inactivity.");
finish();
Toast.makeText(HomeActivity.this, "Logged out after 3 minutes on inactivity.", Toast.LENGTH_SHORT).show();
}
};
startHandler();
}
public void stopHandler() {
handler.removeCallbacks(r);
Log.d("HandlerRun", "stopHandlerMain");
}
public void startHandler() {
handler.postDelayed(r, 3 * 60 * 1000);
Log.d("HandlerRun", "startHandlerMain");
}
@Override
public void onUserInteraction() {
super.onUserInteraction();
stopHandler();
startHandler();
}
@Override
protected void onPause() {
stopHandler();
Log.d("onPause", "onPauseActivity change");
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
startHandler();
Log.d("onResume", "onResume_restartActivity");
}
@Override
protected void onDestroy() {
super.onDestroy();
stopHandler();
Log.d("onDestroy", "onDestroyActivity change");
}
}
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 方法中,您可以在回调中指定要执行的操作...
idleTimer = new IdleTimer(60000, new IIdleCallback() {
@Override
public void inactivityDetected() {
...your move...
}
});
idleTimer.startIdleTimer();