首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 實現用戶長時間無操作自動退出登錄功能

     編輯:程式設計綜合問答

設計思路

  • 定義 BaseActivity 作為所有頁面父類。
  • 重寫 dispatchTouchEvent() 記錄最後操作時間戳。
  • 啟動 Timer 定期檢查間隔,超時則觸發登出邏輯。

完整實現代碼

1. BaseActivity

public abstract class BaseActivity extends AppCompatActivity {
    private static final long TIMEOUT_MS = 5 * 60 * 1000; // 5 分鐘
    private static Timer sTimer;
    private static long sLastTouchTime = System.currentTimeMillis();

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        sLastTouchTime = System.currentTimeMillis();
        return super.dispatchTouchEvent(ev);
    }

    @Override
    protected void onResume() {
        super.onResume();
        startTimer();
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 可選:後台不計時,視業務而定
    }

    private static void startTimer() {
        if (sTimer != null) return;
        sTimer = new Timer(true); // 守護線程
        sTimer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                if (System.currentTimeMillis() - sLastTouchTime > TIMEOUT_MS) {
                    // 切換到主線程執行登出
                    new Handler(Looper.getMainLooper()).post(() -> {
                        logoutAllActivities();
                    });
                    stopTimer();
                }
            }
        }, 0, 1000); // 每秒檢查一次
    }

    private static void stopTimer() {
        if (sTimer != null) {
            sTimer.cancel();
            sTimer = null;
        }
    }

    private static void logoutAllActivities() {
        // 方案 A:發送廣播通知所有 Activity finish
        Intent intent = new Intent("ACTION_FORCE_LOGOUT");
        LocalBroadcastManager.getInstance(getAppContext()).sendBroadcast(intent);
        
        // 方案 B:維護 Activity 棧列表逐個 finish (需 Application 管理)
        // ActivityStackManager.getInstance().finishAll();
        
        // 方案 C:啟動登錄頁並清空棧
        Intent login = new Intent(getAppContext(), LoginActivity.class);
        login.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
        getAppContext().startActivity(login);
    }
    
    // 獲取 Application Context 的靜態方法 (需在 Application 子類中實現)
    private static Context getAppContext() { return MyApplication.getInstance(); }
}

2. 子 Activity 註冊廣播

public class MainActivity extends BaseActivity {
    private BroadcastReceiver mLogoutReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            finish();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LocalBroadcastManager.getInstance(this).registerReceiver(mLogoutReceiver, 
            new IntentFilter("ACTION_FORCE_LOGOUT"));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mLogoutReceiver);
    }
}

關鍵點說明

要點說明
靜態變量Timer、lastTouchTime 為 static,全進程共享,避免多 Activity 多次創建定時器
守護線程new Timer(true) 不阻塞進程退出
主線程切換UI 操作 (finish/startActivity) 必須在主線程,用 Handler.post
清理註冊onDestroy 取消註冊廣播,防內存洩漏
配置化超時時間、檢查間隔建議放入配置文件/SharedPreferences

替代方案

  • JobScheduler / WorkManager:系統級定時任務,進程被殺也能觸發,但最小間隔 15 分鐘,不適合精確 5 分鐘需求。
  • RxJava/RxAndroid:Observable.interval(1, TimeUnit.SECONDS) + takeUntil 實現更優雅。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved