如何检测Android中的用户不活动状态

AKh*_*AKh 93 android user-inactivity

用户启动我的应用程序并登录.
选择会话超时为5分钟.
在应用程序上执行某些操作.(全部在前台)
现在用户将Myapp带到后台并启动其他应用程序.
---->倒计时器启动并在5分钟后退出用户
或用户关闭屏幕.
---->倒计时器启动并在5分钟后退出用户

我想要相同的行为,即使应用程序在前台,但用户不会长时间说6-7分钟与应用程序交互.假设屏幕始终处于开启状态.我想检测用户的不活动状态(即使应用程序位于前台,也没有与应用程序进行交互)并启动我的倒数计时器.

gfr*_*gon 104

根据Fredrik Wallenius的回答,我提出了一个很简单的解决方案.这是一个需要由所有活动扩展的基本活动类.

public class MyBaseActivity extends Activity {

    public static final long DISCONNECT_TIMEOUT = 300000; // 5 min = 5 * 60 * 1000 ms


    private Handler disconnectHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            // todo
            return true;
        }
    });

    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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这将为创建的每个`Activity`创建`Handler`和`Runnable`的多个实例.如果我们将这两个成员转换为`static`,这将被避免.另外,你能告诉我为什么你在`onStop()`中调用`stopDisconnectTimer()`? (3认同)

Fre*_*ius 84

我不知道跟踪不活动的方法,但有一种方法可以跟踪用户活动.您可以捕获onUserInteraction()在您的活动中调用的回调,每次用户与应用程序进行任何交互时都会调用该回调.我建议做这样的事情:

@Override
public void onUserInteraction(){
    MyTimerClass.getInstance().resetTimer();
}
Run Code Online (Sandbox Code Playgroud)

如果您的应用程序包含多个活动,为什么不将此方法放在抽象超类(扩展Activity)中,然后让所有活动扩展它.

  • 我还没有计时,但我会说重置像这样的计时器lastInteraction = System.currentTimeMillis(); 比如2毫秒.每分钟做60次,你"松散"120ms.超过60000. (3认同)
  • 在某些情况下,没有调用onUserInteraction()(对话框不调用它,并且在微调器中滚动)是否有针对这些情况的解决方法? (3认同)

小智 17

我认为你应该使用这段代码,这是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 
}
Run Code Online (Sandbox Code Playgroud)


AKh*_*AKh 8

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;
          }
        }
      }
    }
Run Code Online (Sandbox Code Playgroud)

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);
      }
    }
Run Code Online (Sandbox Code Playgroud)

  • @Nappy:那么请解释一下这样做的正确方法.你的评论含糊不清,优柔寡断. (4认同)
  • @AKh:其他答案已经显示了可能性.在您的解决方案中,我看不到每15秒轮询的任何好处.它会产生相同的效果,因为你在"ACTION_SCREEN_OFF"上启动一个计时器,随机持续时间为0-15秒.这没有意义.. (2认同)
  • 你能为`isInForeGrnd`提供代码片段吗? (2认同)

soe*_*nke 7

@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));
}
Run Code Online (Sandbox Code Playgroud)


Com*_*are 5

除了ACTION_SCREEN_OFFACTION_USER_PRESENT广播,在OS级别上没有“用户不活动”的概念。您将必须在自己的应用程序中以某种方式定义“不活动”。