簡體   English   中英

如何檢測 Android 中的用戶不活動

[英]How to detect user inactivity in Android

用戶啟動我的應用程序並登錄。
選擇 Session 超時為 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();
    }
}

我不知道跟蹤不活動的方法,但有一種跟蹤用戶活動的方法。 您可以在您的活動中捕獲一個名為onUserInteraction()的回調,每次用戶與應用程序進行任何交互時都會調用該回調。 我建議做這樣的事情:

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

如果您的應用程序包含多個活動,為什么不將此方法放在抽象超類中(擴展Activity ),然后讓所有活動擴展它。

我認為您應該使用此代碼,這是 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 
}
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);
      }
    }
@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));
}

除了ACTION_SCREEN_OFFACTION_USER_PRESENT廣播之外,在操作系統級別沒有“用戶不活動”的概念。 您必須在自己的應用程序中以某種方式定義“不活動”。

甚至您也可以使用@gfrigon@AKh解決方案來管理您的需求。

但是,這是計時器和處理程序的免費解決方案 我已經為此做好了良好的計時器解決方案。 但是我已經成功實現了Timer和Handler的免費解決方案。

首先,我告訴您使用計時器或處理程序時必須管理的內容

  • 如果您的應用被用戶或優化器殺死,則您的應用將永遠不會自動注銷,因為所有回調都已銷毀。 管理一些警報管理器或服務?
  • 每個基類都有計時器好嗎? 您正在為調用注銷過程創建許多線程( 在應用程序級別管理靜態處理程序還是計時器? )。
  • 如果用戶在后台該怎么辦,如果用戶在應用程序外執行其他工作,則處理程序將啟動“登錄活動”。 管理應用程序的前台還是后台? )。
  • 屏幕自動關閉怎么辦。 (是否在廣播接收器上關閉屏幕?

最后,我實現了一個解決方案

  1. 沒有處理程序或計時器。
  2. 否警報管理器。
  3. 不管理App LifeCycle。
  4. ACTION_SCREEN_ON / ACTION_SCREEN_OFF廣播接收器。

最簡單可靠的解決方案

我們不會通過計時器觀察用戶的不活動狀態,而是會根據用戶活動檢查上次活動時間。 因此,當用戶下次與應用進行互動時,我會檢查上一次的互動時間。

這是BaseActivity.class ,您將從每個活動類(而不是LoginActivity 您將在此類中的字段TIMEOUT_IN_MILLI中定義注銷時間。

import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

public class BaseActivity extends AppCompatActivity {
    public static final long TIMEOUT_IN_MILLI = 1000 * 20;
    public static final String PREF_FILE = "App_Pref";
    public static final String KEY_SP_LAST_INTERACTION_TIME = "KEY_SP_LAST_INTERACTION_TIME";

    @Override
    public void onUserInteraction() {
        super.onUserInteraction();
        if (isValidLogin())
            getSharedPreference().edit().putLong(KEY_SP_LAST_INTERACTION_TIME, System.currentTimeMillis()).apply();
        else logout();
    }

    public SharedPreferences getSharedPreference() {
        return getSharedPreferences(PREF_FILE, MODE_PRIVATE);
    }

    public boolean isValidLogin() {
        long last_edit_time = getSharedPreference().getLong(KEY_SP_LAST_INTERACTION_TIME, 0);
        return last_edit_time == 0 || System.currentTimeMillis() - last_edit_time < TIMEOUT_IN_MILLI;
    }

    public void logout() {
        Intent intent = new Intent(this, LoginActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
        finish();
        Toast.makeText(this, "User logout due to inactivity", Toast.LENGTH_SHORT).show();
        getSharedPreference().edit().remove(KEY_SP_LAST_INTERACTION_TIME).apply(); // make shared preference null.
    }
}

在我的活動基類中,我創建了受保護的類:

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

在搜索過程中,我找到了很多答案,但這是我得到的最佳答案。 但此代碼的局限性在於它僅適用於活動而不適用於整個應用程序。 以此為參考。

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

用戶不活動可以使用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");

    }

}

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

這是一個完整的解決方案,可在幾分鍾(例如 3 分鍾)后處理用戶不活動。 解決了App在后台超時時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();
        }

    }

}

接下來,我們為我們的“注銷監聽器”創建一個接口

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>

我認為需要將計時器與上次活動時間相結合。

所以像這樣:

  1. 在 onCreate(Bundle savedInstanceState) 啟動一個計時器,說 5 分鍾

  2. 在 onUserInteraction() 中只存儲當前時間

到目前為止非常簡單。

現在,當計時器彈出時,請執行以下操作:

  1. 取當前時間減去存儲的交互時間得到timeDelta
  2. 如果 timeDelta >= 5 分鍾,你就完成了
  3. 如果 timeDelta 小於 5 分鍾,則再次啟動計時器,但這次使用 5 分鍾 - 存儲的時間。 換句話說,5分鍾形成最后一次互動

我遇到了與 SO 問題類似的情況,我需要跟蹤用戶不活動 1 分鍾,然后重定向用戶以啟動 Activity,我還需要清除活動堆棧。

基於@gfrigon 的回答,我想出了這個解決方案。

操作欄.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:清除活動堆棧

這個 Handler 類應該是靜態的,否則可能會發生泄漏

最好的辦法是通過在 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);
}
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。

真正的方法

您可以使用此技術來檢測用戶不活動的時間(即使應用程序處於后台)。

  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. 將此mMillisUntilFinished變量和當前時間保存在onStop() 的共享首選項中。
@Override
    protected void onStop() {
        super.onStop();
        editor.putLong("millisUntilFinished",mMillisUntilFinished);
        editor.putLong("userExitedMillis",System.currentTimeMillis());
        editor.apply();
    }

提示如果您從System.currentTimeMillis()減去userExitedMillis ,那么您將獲得活動非活動時間(以毫秒為單位)

多個活動的解決方案,即使應用程序在后台也可用

所以我看到接受的答案僅支持 1 個活動,而且如果用戶最小化應用程序,則不會發生 DC 回調 所以我最終修改了 gfrigon 的答案並修復了它們:

public class SActivity extends AppCompatActivity {

    private static Handler dcHandler = new Handler();
    public static Runnable dcCallback = null;
    public static long dcTimeout = 30000; // 30 seconds here for example, you can update it just by calling dcTimeout = x; in your activities that extend this class
    public static boolean internalCause;
    public static boolean dcRequestWhileInBackground;
    public static boolean activityFocusGone;

    public static void resetDisconnectTimer() {
        dcHandler.removeCallbacks(dcCallback);
        dcHandler.postDelayed(dcCallback, dcTimeout);
    }

    public static void stopDisconnectTimer() {
        dcHandler.removeCallbacks(dcCallback);
    }

    @Override
    public void onUserInteraction() {
        resetDisconnectTimer();
    }

    @Override
    protected void onPause() {
        super.onPause();
        activityFocusGone = true;
    }

    @Override
    public void onResume() {
        super.onResume();

        resetDisconnectTimer();
        activityFocusGone = false;
        if (dcRequestWhileInBackground && !internalCause) {
            dcRequestWhileInBackground = false;
            dcCallback.run();
        }
        internalCause = false;
    }
}

基本上你需要做的是:

  1. 從上面的 class 擴展你的所有活動(你的LockscreenActivity除外)
  2. dcCallback之后打開的第一個活動中設置LockscreenActivity (順便說一句,它必須擴展SActivity
        dcCallback = () -> {
            if (activityFocusGone)
                SActivity.dcRequestWhileInBackground = true;
            startActivity(new Intent(getApplicationContext(), Lockscreen.class));
        };
  1. 將這兩行放在您想要保護的所有其他剩余類的onCreate方法中(以避免啟動多個LockscreenActivity並防止應用程序在用戶切換活動后被鎖定)
internalCause = true;
resetDisconnectTimer();

可能為時已晚,可能有比這更好的解決方案,但希望這對某人有所幫助:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM