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

Android 計時器螢幕關閉後停止:用 AlarmManager ELAPSED_REALTIME_WAKEUP 替代 Timer 實現真後台運行

     編輯:程式設計疑難解答

為何 Timer 會停止?

  • Timer / TimerTask 運行在普通線程,**進程進入 Doze 模式或被系統回收時會暫停**。
  • 螢幕關閉 → 系統進入休眠 → CPU 降頻/核心掉線 → Timer 執行緒凍結。

正解:AlarmManager + WakeLock

public class TimerService extends Service {
    private AlarmManager alarmManager;
    private PendingIntent pendingIntent;

    @Override
    public void onCreate() {
        super.onCreate();
        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        Intent intent = new Intent(this, TimerReceiver.class);
        pendingIntent = PendingIntent.getBroadcast(this, 0, intent,
            PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 每秒觸發,ELAPSED_REALTIME_WAKEUP 會喚醒 CPU
        alarmManager.setRepeating(
            AlarmManager.ELAPSED_REALTIME_WAKEUP,
            SystemClock.elapsedRealtime() + 1000,
            1000,
            pendingIntent
        );
        return START_STICKY; // 進程被殺自動重啟
    }

    @Override
    public void onDestroy() {
        alarmManager.cancel(pendingIntent);
        super.onDestroy();
    }
}

// BroadcastReceiver 處理計時邏輯
public class TimerReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 更新倒計時、發送廣播通知 UI、寫入資料庫等
        // 注意:onReceive 運行在主線程,耗時操作需啟動 Service/Thread
    }
}

清單檔聲明

<service android:name=".TimerService"
    android:foregroundServiceType="dataSync" />  <!-- Android 14+ 前台服務類型 -->
<receiver android:name=".TimerReceiver"
    android:exported="false" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <!-- Android 12+ -->

進階:WorkManager(推薦延遲可容忍任務)

PeriodicWorkRequest timerWork = new PeriodicWorkRequest.Builder(
    TimerWorker.class, 15, TimeUnit.MINUTES) // 最小 15 分鐘
    .setConstraints(new Constraints.Builder()
        .setRequiresBatteryNotLow(true)
        .build())
    .build();
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
    "timer_work", ExistingPeriodicWorkPolicy.KEEP, timerWork);

⚠️ WorkManager **最小間隔 15 分鐘**,不適合秒級倒計時,但電池友好、系統自動調度。

總結

Timer 不適合螢幕關閉後持續運行**。請使用 AlarmManager.ELAPSED_REALTIME_WAKEUP(秒級精確)或 WorkManager(延遲容忍、省電),並聲明 WAKE_LOCK、SCHEDULE_EXACT_ALARM 權限,配合 START_STICKY 服務實現真後台計時。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved