You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用AlarmManager设置周期性提醒?求多目标提醒实现教程

Hey there! Let's walk through how to build this reminder system for your app—this is a super common scenario, so I’ll break it down into actionable steps with code examples and key tips.

1. Core Implementation Overview

Here’s the big-picture workflow you’ll need to follow:

  • Fetch all reminder configurations from your SQLite database when the app starts (or when configurations are updated).
  • For each reminder, calculate the exact trigger time based on its type (one-time date or weekly repeat).
  • Use AlarmManager to schedule the reminder, ensuring it fires even in Doze mode (critical for modern Android versions).
  • When the alarm triggers, broadcast an intent to show a system notification. For weekly repeats, re-schedule the next alarm after the current one fires.
2. Fetching Reminder Configs from SQLite

First, let’s assume your reminders table has columns like:
id (unique ID), target_name (your goal’s name), trigger_type (0 for one-time date, 1 for weekly), trigger_date (ISO string for one-time triggers), trigger_weekdays (bitmask or comma-separated values for days e.g., "1,3" for Monday/Wednesday), trigger_time (HH:mm string).

Here’s how you might load these into a model class:

// Example Reminder POJO
public class Reminder {
    private int id;
    private String targetName;
    private int triggerType;
    private Date triggerDate;
    private List<Integer> triggerWeekdays; // 1=Monday, 7=Sunday
    private LocalTime triggerTime;

    // Getters and setters
}

// Fetch from SQLite
public List<Reminder> loadActiveReminders(SQLiteDatabase db) {
    List<Reminder> reminders = new ArrayList<>();
    Cursor cursor = db.rawQuery("SELECT * FROM reminders WHERE is_active = 1", null);
    
    while (cursor.moveToNext()) {
        Reminder rem = new Reminder();
        rem.setId(cursor.getInt(cursor.getColumnIndexOrThrow("id")));
        rem.setTargetName(cursor.getString(cursor.getColumnIndexOrThrow("target_name")));
        rem.setTriggerType(cursor.getInt(cursor.getColumnIndexOrThrow("trigger_type")));
        
        // Parse date, weekdays, and time based on your storage format
        // ...
        
        reminders.add(rem);
    }
    cursor.close();
    return reminders;
}
3. Scheduling Reminders with AlarmManager

AlarmManager is the Android system service for scheduling future events. We’ll handle both one-time and weekly repeat cases.

3.1 One-Time Date Reminders

For a specific date and time, calculate the target timestamp and use setExactAndAllowWhileIdle (to bypass Doze mode):

private void scheduleOneTimeReminder(Context context, Reminder reminder) {
    Calendar targetCal = Calendar.getInstance();
    targetCal.setTime(reminder.getTriggerDate());
    targetCal.set(Calendar.HOUR_OF_DAY, reminder.getTriggerTime().getHour());
    targetCal.set(Calendar.MINUTE, reminder.getTriggerTime().getMinute());
    targetCal.set(Calendar.SECOND, 0);

    long triggerMillis = targetCal.getTimeInMillis();
    // If the target time is in the past, skip or adjust (up to your logic)
    if (triggerMillis < System.currentTimeMillis()) return;

    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context, ReminderReceiver.class);
    intent.putExtra("REMINDER_ID", reminder.getId());
    
    // Ensure unique PendingIntent using the reminder ID as request code
    PendingIntent pendingIntent = PendingIntent.getBroadcast(
        context,
        reminder.getId(),
        intent,
        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
    );

    // Schedule exact alarm that works in Doze mode
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerMillis, pendingIntent);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerMillis, pendingIntent);
    } else {
        alarmManager.set(AlarmManager.RTC_WAKEUP, triggerMillis, pendingIntent);
    }
}

3.2 Weekly Repeating Reminders

For weekly repeats, you’ll need to handle each selected weekday individually. Note that setRepeating is imprecise on API 19+, so we’ll use exact alarms and re-schedule after each trigger:

private void scheduleWeeklyReminder(Context context, Reminder reminder) {
    for (int weekday : reminder.getTriggerWeekdays()) {
        Calendar targetCal = Calendar.getInstance();
        // Map your weekday value to Calendar constants (1=Monday → Calendar.MONDAY)
        targetCal.set(Calendar.DAY_OF_WEEK, weekday);
        targetCal.set(Calendar.HOUR_OF_DAY, reminder.getTriggerTime().getHour());
        targetCal.set(Calendar.MINUTE, reminder.getTriggerTime().getMinute());
        targetCal.set(Calendar.SECOND, 0);

        // If today's weekday has passed, set to next week
        if (targetCal.getTimeInMillis() < System.currentTimeMillis()) {
            targetCal.add(Calendar.WEEK_OF_YEAR, 1);
        }

        long triggerMillis = targetCal.getTimeInMillis();
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, ReminderReceiver.class);
        intent.putExtra("REMINDER_ID", reminder.getId());
        intent.putExtra("WEEKDAY", weekday); // Pass weekday to re-schedule later

        PendingIntent pendingIntent = PendingIntent.getBroadcast(
            context,
            reminder.getId() * 10 + weekday, // Unique request code per weekday
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerMillis, pendingIntent);
        } else {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerMillis, pendingIntent);
        }
    }
}
4. Triggering Notifications with a BroadcastReceiver

Create a BroadcastReceiver to handle alarm triggers and show notifications. For weekly repeats, re-schedule the next alarm here:

public class ReminderReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        int reminderId = intent.getIntExtra("REMINDER_ID", -1);
        if (reminderId == -1) return;

        // Fetch reminder details from SQLite
        Reminder reminder = getReminderById(context, reminderId);
        if (reminder == null) return;

        // Show notification
        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "REMINDER_CHANNEL")
                .setSmallIcon(R.drawable.ic_reminder)
                .setContentTitle("Goal Reminder")
                .setContentText("Time to work on: " + reminder.getTargetName())
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setAutoCancel(true);

        notificationManager.notify(reminderId, builder.build());

        // Re-schedule weekly reminder
        if (reminder.getTriggerType() == 1) {
            int weekday = intent.getIntExtra("WEEKDAY", -1);
            if (weekday != -1) {
                Calendar nextCal = Calendar.getInstance();
                nextCal.set(Calendar.DAY_OF_WEEK, weekday);
                nextCal.set(Calendar.HOUR_OF_DAY, reminder.getTriggerTime().getHour());
                nextCal.set(Calendar.MINUTE, reminder.getTriggerTime().getMinute());
                nextCal.add(Calendar.WEEK_OF_YEAR, 1);

                // Re-schedule the exact alarm for next week
                AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
                Intent nextIntent = new Intent(context, ReminderReceiver.class);
                nextIntent.putExtra("REMINDER_ID", reminderId);
                nextIntent.putExtra("WEEKDAY", weekday);

                PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    context,
                    reminderId * 10 + weekday,
                    nextIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
                );

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextCal.getTimeInMillis(), pendingIntent);
                } else {
                    alarmManager.setExact(AlarmManager.RTC_WAKEUP, nextCal.getTimeInMillis(), pendingIntent);
                }
            }
        }
    }

    // Helper method to fetch reminder from DB
    private Reminder getReminderById(Context context, int id) {
        // Implement your SQLite query here
        return null;
    }
}

Don’t forget to register the receiver in your AndroidManifest.xml:

<receiver android:name=".ReminderReceiver" />
5. Critical Tips for Reliability
  • Notification Channels: Android 8.0+ requires a notification channel. Create one on app startup:
    private void createReminderChannel(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                "REMINDER_CHANNEL",
                "Goal Reminders",
                NotificationManager.IMPORTANCE_DEFAULT
            );
            channel.setDescription("Notifications for your goal reminders");
            NotificationManager manager = context.getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }
    
  • Cancel Old Alarms: When a reminder is edited or deleted, cancel its associated PendingIntent using alarmManager.cancel(pendingIntent).
  • Handle Reboots: If you want reminders to persist after a device reboot, register a BootCompletedReceiver to re-schedule all active reminders when the device starts.

内容的提问来源于stack exchange,提问作者Abaneel Jahid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:32:32