【问题标题】:How to detect user inactivity in Android如何检测Android中的用户不活动
【发布时间】:2011-05-11 15:48:51
【问题描述】:

用户启动我的应用并登录。
选择会话超时为 5 分钟。
对应用程序进行一些操作。 (全部在前台)
现在用户将 Myapp 带到后台并启动其他应用程序。
----> 倒计时开始并在 5 分钟后注销用户
或用户关闭屏幕。
----> 倒计时开始并在 5 分钟后注销用户

即使应用程序在前台,但用户长时间不与应用程序交互,例如 6-7 分钟,我也想要相同的行为。假设屏幕一直处于开启状态。我想检测一种用户不活动(即使应用在前台,也没有与应用交互)并启动我的倒计时。

【问题讨论】:

  • 您能否始终让计时器运行并在用户执行某项操作时重置它?

标签: android user-inactivity


【解决方案1】:

根据 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 创建多个HandlerRunnable 实例。如果我们将这两个成员转换为static,就可以避免这种情况。另外,你能告诉我你为什么在onStop()中打电话给stopDisconnectTimer()吗?`
  • @Gaurav 就我而言,这仅在一项活动中实现(因此我没有发现static 修饰符的问题)。至于onStop(),据我所知,我调用onBackPressed() 是为了在断开回调中返回登录屏幕,而断开回调又调用onStop() 方法。当用户手动返回登录屏幕时,通过按返回,计时器也需要停止,因此onStop() 中的stopDisconnectTimer()。我想这部分取决于您的需求和实施。
  • @gfrigon 是否可以将用户重定向到登录活动?
  • @Apostrifix,当然可以。就我而言,只有一项活动:调用onBackPressed() vas 就足够了。如果您的堆栈中有多个活动,则只需为此创建一个意图。您可能需要查看以下答案以清除 Activity 任务(并防止用户重新连接):stackoverflow.com/questions/7075349/…
  • 干得好!我为可运行对象添加了 getter 和 setter,然后根据需要使用 onCreate 方法将其设置在扩展类中......完美,再次感谢。
【解决方案2】:

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

@Override
public void onUserInteraction(){
    MyTimerClass.getInstance().resetTimer();
}

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

【讨论】:

  • 是的,这是一种方法......但是我的应用程序有 30 个不同的活动,当用户处于活动状态时会有太多的交互......所以每次重置计时器都需要昂贵的操作......在最坏的情况下可以在一分钟内完成 50 到 60 次。
  • 我还没有计时,但我会说像这样重置计时器 lastInteraction = System.currentTimeMillis();比如说,2 毫秒。每分钟做 60 次,你会“放松”120 毫秒。超过 60000 个。
  • Fredrik... 我也在使用您的建议来满足这种情况。屏幕超时设置为设备上的最大 30 分钟。 MyApp shd 15 分钟后超时...如果用户超过 1 分钟没有触摸屏幕上的任何内容,那么我将启动 15 分钟注销计时器...。在这种情况下,我将检查差异(lastInteractionTime 和 System.currentTimeMills( )) 超过 1 分钟...然后开火..
  • onUserInteraction() 在某些情况下不会被调用,但是(对话框不会调用它,并且在微调器中滚动)是否有解决这些情况的方法?
  • 你能分享你的 MyTimerClass 吗?
【解决方案3】:

我认为你应该使用这段代码,这是 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 
}

【讨论】:

  • 你用 onUserInteraction 救了我的命
【解决方案4】:
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);
      }
    }

【讨论】:

  • @Nappy:那么请解释一下正确的做法。您的评论含糊不清且优柔寡断。
  • @AKh:其他答案已经显示了可能性。在您的解决方案中,我看不到每 15 秒轮询一次的任何好处。当您在“ACTION_SCREEN_OFF”上启动一个具有 0-15 秒随机持续时间的计时器时,它会产生相同的效果。这只是没有意义..
  • @Nappy:每 15 秒我不仅会检查 SCREEN_ON 或 SCREEN_OFF,还会检查用户的最后一次交互时间和 App 前台状态。基于这三个因素,我对用户与应用交互的活跃程度做出了合乎逻辑的决定。
  • 请完成您的评论。 ....“如果你的 isScreenof 布尔值是?”并且还必须考虑应用程序的前景状态。
  • 这段代码充满了错误,一些变量没有初始化。
【解决方案5】:
@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));
}

【讨论】:

  • 这是解决方案的基础,其余的可以根据您的特殊需求和应用程序架构复杂性进行修改!感谢您的回答!
  • 如何在应用类中应用这个
  • 简洁的解决方案!非常感谢!
【解决方案6】:

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

【讨论】:

    【解决方案7】:

    在 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
    }
    

    【讨论】:

      【解决方案8】:

      在我的活动基类中,我创建了受保护的类:

      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();
      

      【讨论】:

      • 如何检查用户是否处于非活动状态??来自系统的任何输入?
      【解决方案9】:

      在搜索过程中,我找到了很多答案,但这是我得到的最佳答案。但此代码的局限性在于它仅适用于活动而不适用于整个应用程序。以此作为参考。

      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 秒后完成。

      【讨论】:

        【解决方案10】:

        可以在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");
        
            }
        
        }
        

        【讨论】:

          【解决方案11】:

          这是一个完整的解决方案,可以在几分钟(例如 3 分钟)后处理用户不活动。 解决了App在后台超时Activity跳到前台等常见问题。

          首先,我们创建一个所有其他 Activity 都可以扩展的 BaseActivity。

          这是 BaseActivity 代码。

          package com.example.timeout;
          
          import android.app.Activity;
          import android.app.Dialog;
          import android.content.Context;
          import android.content.Intent;
          import android.os.Bundle;
          import android.text.TextUtils;
          import android.view.View;
          import android.view.Window;
          import android.widget.TextView;
          
          import androidx.appcompat.app.AppCompatActivity;
          
          
          import javax.annotation.Nullable;
          
          public class BaseActivity extends AppCompatActivity implements LogoutListener {
          
              private Boolean isUserTimedOut = false;
              private static Dialog mDialog;
          
          
          
              @Override
              protected void onCreate(@Nullable Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
          
                  ((TimeOutApp) getApplication()).registerSessionListener(this);
                  ((TimeOutApp) getApplication()).startUserSession();
          
              }
          
              @Override
              public void onUserInteraction() {
                  super.onUserInteraction();
          
          
              }
          
              @Override
              protected void onResume() {
                  super.onResume();
          
                  if (isUserTimedOut) {
                      //show TimerOut dialog
                      showTimedOutWindow("Time Out!", this);
          
                  } else {
          
                      ((TimeOutApp) getApplication()).onUserInteracted();
          
                  }
          
              }
          
              @Override
              public void onSessionLogout() {
          
          
                  isUserTimedOut = true;
          
              }
          
          
              public void showTimedOutWindow(String message, Context context) {
          
          
                  if (mDialog != null) {
                      mDialog.dismiss();
                  }
                  mDialog = new Dialog(context);
          
          
                  mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
                  mDialog.setContentView(R.layout.dialog_window);
          
                  mDialog.setCancelable(false);
                  mDialog.setCanceledOnTouchOutside(false);
          
                  TextView mOkButton = (TextView) mDialog.findViewById(R.id.text_ok);
                  TextView text_msg = (TextView) mDialog.findViewById(R.id.text_msg);
          
                  if (message != null && (!TextUtils.isEmpty(message)) && (!message.equalsIgnoreCase("null"))) {
                      text_msg.setText(message);
          
                  }
          
          
                  mOkButton.setOnClickListener(new View.OnClickListener() {
                      @Override
                      public void onClick(View v) {
          
                          if (mDialog != null){
          
                              mDialog.dismiss();
          
                              Intent intent = new Intent(BaseActivity.this, LoginActivity.class);
                              intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                              startActivity(intent);
          
                              finish();
                          }
          
          
                      }
                  });
          
                  if(!((Activity) context).isFinishing())
                  {
                      //show dialog
                      mDialog.show();
                  }
          
              }
          
          }
          

          接下来,我们为“Logout Listener”创建一个接口

          package com.example.timeout;
          
          public interface LogoutListener {
          
              void onSessionLogout();
          
          }
          

          最后,我们创建一个扩展“应用程序”的 Java 类

          package com.example.timeout;
          
          import android.app.Application;
          
          import java.util.Timer;
          import java.util.TimerTask;
          
          public class TimeOutApp extends Application {
          
              private LogoutListener listener;
              private Timer timer;
              private static final long INACTIVE_TIMEOUT = 180000; // 3 min
          
          
              public void startUserSession () {
                  cancelTimer ();
          
                  timer = new Timer ();
                  timer.schedule(new TimerTask() {
                      @Override
                      public void run() {
          
                          listener.onSessionLogout ();
          
                      }
                  }, INACTIVE_TIMEOUT);
          
              }
          
              private void cancelTimer () {
                  if (timer !=null) timer.cancel();
              }
          
              public void registerSessionListener(LogoutListener listener){
                  this.listener = listener;
              }
          
              public void onUserInteracted () {
                  startUserSession();
              }
          
          
          }
          

          注意:不要忘记将“TimeOutApp”类添加到清单文件中的应用程序标签

          <application
                  android:name=".TimeOutApp">
                  </application>
          

          【讨论】:

            【解决方案12】:

            我认为需要将计时器与上次活动时间相结合。

            像这样:

            1. 在 onCreate(Bundle savedInstanceState) 中启动一个计时器,比如 5 分钟

            2. 在 onUserInteraction() 中只存储当前时间

            到目前为止非常简单。

            现在当计时器弹出时这样做:

            1. 以当前时间减去存储的交互时间得到timeDelta
            2. 如果 timeDelta >= 5 分钟,您就完成了
            3. 如果 timeDelta

            【讨论】:

              【解决方案13】:

              我遇到了与 SO 问题类似的情况,我需要跟踪用户不活动 1 分钟然后重定向用户以启动 Activity,我还需要清除 Activity 堆栈。

              根据@gfrigon 的回答,我想出了这个解决方案。

              ActionBar.java

              public abstract class ActionBar extends AppCompatActivity {
              
                  public static final long DISCONNECT_TIMEOUT = 60000; // 1 min
              
                  private final MyHandler mDisconnectHandler = new MyHandler(this);
              
                  private Context mContext;
              
              
                  @Override
                  protected void onCreate(@Nullable Bundle savedInstanceState) {
                      super.onCreate(savedInstanceState);
              
                      mContext = this;
                  }
              
              
              
                  /*
                  |--------------------------------------------------------------------------
                  | Detect user inactivity in Android
                  |--------------------------------------------------------------------------
                  */
              
                  // Static inner class doesn't hold an implicit reference to the outer class
              
                  private static class MyHandler extends Handler {
              
                      // Using a weak reference means you won't prevent garbage collection
              
                      private final WeakReference<ActionBar> myClassWeakReference;
              
                      public MyHandler(ActionBar actionBarInstance) {
              
                          myClassWeakReference = new WeakReference<ActionBar>(actionBarInstance);
                      }
              
                      @Override
                      public void handleMessage(Message msg) {
              
                          ActionBar actionBar = myClassWeakReference.get();
              
                          if (actionBar != null) {
                              // ...do work here...
                          }
                      }
                  }
              
              
                  private Runnable disconnectCallback = new Runnable() {
              
                      @Override
                      public void run() {
              
                          // Perform any required operation on disconnect
              
                          Intent startActivity = new Intent(mContext, StartActivity.class);
              
                          // Clear activity stack
              
                          startActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
              
                          startActivity(startActivity);
                      }
                  };
              
                  public void resetDisconnectTimer() {
              
                      mDisconnectHandler.removeCallbacks(disconnectCallback);
                      mDisconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT);
                  }
              
                  public void stopDisconnectTimer() {
              
                      mDisconnectHandler.removeCallbacks(disconnectCallback);
                  }
              
                  @Override
                  public void onUserInteraction(){
              
                      resetDisconnectTimer();
                  }
              
                  @Override
                  public void onResume() {
              
                      super.onResume();
                      resetDisconnectTimer();
                  }
              
                  @Override
                  public void onStop() {
              
                      super.onStop();
                      stopDisconnectTimer();
                  }
              }
              

              补充资源

              Android: Clear Activity Stack

              This Handler class should be static or leaks might occur

              【讨论】:

                【解决方案14】:

                最好的办法是通过在 Application calss 中注册 AppLifecycleCallbacks 在整个应用程序中处理此问题(假设您有多个活动)。您可以在 Application 类中使用 registerActivityLifecycleCallbacks() 和以下回调(我建议创建一个扩展 ActivityLifecycleCallbacks 的 AppLifecycleCallbacks 类):

                public interface ActivityLifecycleCallbacks {
                    void onActivityCreated(Activity activity, Bundle savedInstanceState);
                    void onActivityStarted(Activity activity);
                    void onActivityResumed(Activity activity);
                    void onActivityPaused(Activity activity);
                    void onActivityStopped(Activity activity);
                    void onActivitySaveInstanceState(Activity activity, Bundle outState);
                    void onActivityDestroyed(Activity activity);
                }
                

                【讨论】:

                  【解决方案15】:
                  open class SubActivity : AppCompatActivity() {
                      var myRunnable:Runnable
                      private var myHandler = Handler()
                  
                      init {
                          myRunnable = Runnable{
                              toast("time out")
                              var intent = Intent(this, MainActivity::class.java)
                              startActivity(intent)
                  
                          }
                      }
                  
                      fun toast(text: String) {
                          runOnUiThread {
                              val toast = Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT)
                              toast.show()
                          }
                      }
                  
                     override fun onUserInteraction() {
                          super.onUserInteraction();
                          myHandler.removeCallbacks(myRunnable)
                          myHandler.postDelayed(myRunnable, 3000)
                      }
                  
                      override fun onPause() {
                          super.onPause()
                          myHandler.removeCallbacks(myRunnable)
                      }
                  
                      override fun onResume() {
                              super.onResume()
                              myHandler.postDelayed(myRunnable, 3000)
                      }
                  }
                  

                  使用

                  扩展您的活动
                  YourActivity:SubActivity(){}
                  

                  当用户在 YourActivity 上 3000 毫秒后处于非活动状态时进入 MainActivity

                  我使用了以前的答案并将其转换为 kotlin。

                  【讨论】:

                    【解决方案16】:

                    真正的方式

                    您可以使用此技术来检测用户处于非活动状态的时间(即使应用程序处于后台)。

                    1. 创建一个SharedPreference 及其编辑器对象。然后声明 3 个长变量,例如:
                    mMillisUntilFinished = pref.getLong("millisUntilFinished",60*1000); // Replace with your time
                    long userExitedMillis = pref.getLong("userExitedMillis",0);
                    long timeLeft = mMillisUntilFinished - (System.currentTimeMillis() - userExitedMillis);
                    
                    1. timeLeft 传递为millisInFuture。在计时器内部,在每个滴答声中将 millisUntilFinished 分配给一个公共变量
                    new CountDownTimer(timeLeft,1000){
                                @Override
                                public void onTick(long millisUntilFinished) {
                                    Log.d("TAG", "Time left : " + millisUntilFinished/1000 + " sec");
                                    mMillisUntilFinished = millisUntilFinished;
                                }
                    
                                @Override
                                public void onFinish() {
                                    // Timer completed
                                }
                            }.start();
                    
                    
                    1. onStop() 处以共享偏好保存此 mMillisUntilFinished 变量和当前时间。
                    @Override
                        protected void onStop() {
                            super.onStop();
                            editor.putLong("millisUntilFinished",mMillisUntilFinished);
                            editor.putLong("userExitedMillis",System.currentTimeMillis());
                            editor.apply();
                        }
                    

                    说明

                    如果你从System.currentTimeMillis()(用户开始活动的时间)中减去userExitedMillis(用户退出的时间),那么你将得到活动的非活动时间(以毫秒为单位)。只需从timeLeft 中减去此不活动时间即可

                    【讨论】:

                      猜你喜欢
                      • 2014-02-11
                      • 1970-01-01
                      • 2011-03-21
                      • 2021-05-10
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-01-13
                      • 2011-06-09
                      相关资源
                      最近更新 更多