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

Android 定時提醒:應用關閉後仍能彈出通知的實現方案

     編輯:程式設計疑難解答

核心誤區

很多開發者嘗試在 Service 或 BroadcastReceiver 中直接彈窗,或期望普通進程常駐後台。Android 系統為了電量和內存,會回收無前台組件的進程,導致鬧鐘失效。

正確架構:AlarmManager + 高優先級組件

1. 精確鬧鐘 (API 19+)

AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 
    PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);

// 設置精確鬧鐘(API 23+ 需忽略電池優化)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
} else {
    alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
}

2. 接收廣播並彈出通知 (非 Activity)


public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 1. 獲取通知管理器
        NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        
        // 2. Android 8.0+ 必須創建通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                "schedule_channel", "日程提醒", NotificationManager.IMPORTANCE_HIGH);
            nm.createNotificationChannel(channel);
        }
        
        // 3. 構建通知
        Intent clickIntent = new Intent(context, MainActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(context, 0, clickIntent, 
            PendingIntent.FLAG_IMMUTABLE);
            
        Notification notification = new NotificationCompat.Builder(context, "schedule_channel")
            .setContentTitle("日程提醒")
            .setContentText("您有一個日程開始了")
            .setSmallIcon(R.drawable.ic_notification)
            .setContentIntent(contentIntent)
            .setAutoCancel(true)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .build();
            
        // 4. 發送通知(ID 唯一標識)
        nm.notify((int) System.currentTimeMillis(), notification);
    }
}

3. Manifest 註冊(關鍵:exported=true)

<receiver 
    android:name=".AlarmReceiver"
    android:exported="true" 
    android:enabled="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- 開機自啟 -->
    </intent-filter>
</receiver>

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <!-- API 31+ -->
<uses-permission android:name="android.permission.USE_EXACT_ALARM" /> <!-- API 33+ -->

進階:WorkManager 替代方案 (推薦)

WorkManager 封裝了 AlarmManager/JobScheduler,自動適配版本,支持約束條件(網絡、充電、閒置),更適合可延遲的周期性任務:

OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(ReminderWorker.class)
    .setInitialDelay(triggerTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS)
    .addTag("schedule_reminder")
    .build();
WorkManager.getInstance(context).enqueue(work);

關鍵權限與適配清單

Android 版本關鍵要求
6.0 (API 23)忽略電池優化白名單引導 ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
8.0 (API 26)通知渠道、後台執行限制、隱式廣播限制
10 (API 29)後台啟動 Activity 限制
12 (API 31)SCHEDULE_EXACT_ALARM 權限(用戶可拒絕)
14 (API 34)前台服務類型細分、精確鬧鐘更嚴格

總結

應用關閉後提醒的核心是 系統級鬧鐘 + 高優先級通知。不需要 Root、不需要常駐進程。正確使用 AlarmManager.setExactAndAllowWhileIdle 配合 NotificationCompat,並處理好各版本權限適配,即可可靠實現。推薦遷移至 WorkManager 簡化開發。

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