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

Posted

技术标签:

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

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

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

【问题讨论】:

您能否始终让计时器运行并在用户执行某项操作时重置它? 【参考方案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 任务(并防止用户重新连接):***.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】:

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

像这样:

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

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

到目前为止非常简单。

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

    以当前时间减去存储的交互时间得到timeDelta 如果 timeDelta >= 5 分钟,您就完成了 如果 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】:

真正的方式

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

    创建一个SharedPreference 及其编辑器对象。然后声明 3 个长变量,例如:
mMillisUntilFinished = pref.getLong("millisUntilFinished",60*1000); // Replace with your time
long userExitedMillis = pref.getLong("userExitedMillis",0);
long timeLeft = mMillisUntilFinished - (System.currentTimeMillis() - userExitedMillis);
    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();

    onStop() 处以共享偏好保存此 mMillisUntilFinished 变量和当前时间。
@Override
    protected void onStop() 
        super.onStop();
        editor.putLong("millisUntilFinished",mMillisUntilFinished);
        editor.putLong("userExitedMillis",System.currentTimeMillis());
        editor.apply();
    

说明

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

【讨论】:

以上是关于如何检测Android中的用户不活动的主要内容,如果未能解决你的问题,请参考以下文章

Android - 如何检测堆栈中的最终活动

如何在 iOS 和 Android 的给定时间检测用户是不是仅在一台设备上处于活动状态

如何检测android中的活动冻结和滞后原因?

如何在 Flutter 中检测用户不活动

如何保护android中的活动[关闭]

如何检测哪个活动导致服务在 Android 中启动?