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

Android BroadcastReceiver 重啟失效:開機自啟與定時任務持久化方案

     編輯:程式設計綜合問答

核心原因

BroadcastReceiver 註冊於 AndroidManifest.xml(靜態註冊)或 Context.registerReceiver()(動態註冊)。動態註冊隨進程銷毀而失效;靜態註冊雖持久,但 Android 3.1+ 採用「停止狀態」機制:應用被強制停止或用戶從未啟動過,廣播不會喚醒組件。

定時提醒失效的典型場景

  1. 使用 AlarmManager.set() 設置鬧鐘,PendingIntent 指向 BroadcastReceiver。
  2. 手機重啟後,所有 AlarmManager 設置的鬧鐘被清空(非 setExactAndAllowWhileIdle/setAlarmClock 亦會丟失)。
  3. 應用未啟動過或被凍結,BOOT_COMPLETED 廣播無法喚醒 Receiver 重註冊鬧鐘。

完整解決方案:開機自啟 + 重排程

1. 聲明權限與 Receiver

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<receiver
    android:name=".BootReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.QUICKBOOT_POWERON" /> <!-- 部分廠商 -->
    </intent-filter>
</receiver>

<receiver android:name=".AlarmReceiver" android:exported="false" />

2. BootReceiver 重建鬧鐘

public class BootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())
                || "android.intent.action.QUICKBOOT_POWERON".equals(intent.getAction())) {
            // 啟動 Service 重排程,避免主線程超時
            context.startService(new Intent(context, RescheduleService.class));
        }
    }
}

3. RescheduleService 恢復所有定時任務

public class RescheduleService extends IntentService {
    public RescheduleService() { super("RescheduleService"); }
    
    @Override
    protected void onHandleIntent(Intent intent) {
        // 從 SharedPreferences/DB 讀取用戶設置的提醒時間
        List reminders = ReminderRepository.getAll(this);
        AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
        for (Reminder r : reminders) {
            PendingIntent pi = PendingIntent.getBroadcast(this, r.id,
                new Intent(this, AlarmReceiver.class).putExtra("reminder_id", r.id),
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
            // Android 6+ Doze 模式兼容
            if (Build.VERSION.SDK_INT >= 23) {
                am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, r.triggerAtMillis, pi);
            } else if (Build.VERSION.SDK_INT >= 19) {
                am.setExact(AlarmManager.RTC_WAKEUP, r.triggerAtMillis, pi);
            } else {
                am.set(AlarmManager.RTC_WAKEUP, r.triggerAtMillis, pi);
            }
        }
    }
}

4. AlarmReceiver 執行具體提醒邏輯

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        int reminderId = intent.getIntExtra("reminder_id", -1);
        // 彈通知、響鈴、啟動 Activity 等
        NotificationHelper.showReminder(context, reminderId);
    }
}

現代替代方案(推薦)

方案適用場景優勢
WorkManager可延遲、需保證執行的後台任務(同步、備份、日誌上傳)系統級調度、電池優化友好、支援約束條件、跨版本一致
JobScheduler (API 21+)周期性、網絡相關任務系統批次調度、省電
Foreground Service + AlarmManager精確鬧鐘、音樂播放、導航用戶可見、不易被殺

總結:靜態註冊 BOOT_COMPLETED + Service 重排程 是傳統 BroadcastReceiver 方案的正確打開方式。新項目優先評估 WorkManager,僅在需精確到秒的鬧鐘場景保留 AlarmManager 方案。

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