Android Alarm Manager повторяется в определенное время

У меня возникли проблемы с диспетчером аварий в Android. Так что я пытаюсь сделать так, чтобы будильник повторялся для запуска вставки БД каждый день около 12.01.

Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY, 0 );
    calendar.set(Calendar.MINUTE, 1);
        notificationCount = notificationCount + 1;
        AlarmManager mgr = (AlarmManager) context
                .getSystemService(Context.ALARM_SERVICE);
        Intent notificationIntent = new Intent(context,
                ReminderAlarm.class);

        notificationIntent.putExtra("NotifyCount", notificationCount);
        PendingIntent pi = PendingIntent.getBroadcast(context,
                notificationCount, notificationIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
                calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);

В общем, я придумал этот код. Однако диспетчер аварийных сигналов снова запускается через минуту, когда я его установил.

Допустим, я запускаю приложения 01/10/2014 5.48PM. Я хотел, чтобы это запускало вставку БД при onReceive каждый день после того, как я установил его только в 12.01. Но каким-то образом диспетчер аварийных сигналов запускается в 10.10.2014 в 5.49 вечера, то есть через одну минуту после того, как я его установил, и он перестал работать.

Интересно, какую часть я сделал неправильно.

Заранее спасибо.

РЕДАКТИРОВАТЬ

Повторяющийся класс Для этого класса он будет запускать диспетчер аварий каждый день и передавать переменные в класс сигналов напоминаний для вставки БД.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.recurring);
    context = this;
    buildListView();
    if(!alarmInitialized(this)) { 
        scheduleAlarms(this); 
    }
}

// And the few methods you suggested to schedule the alarm
public static void scheduleAlarms(Context context) {
    Calendar calendar = Calendar.getInstance();
    if (hasRunnedToday(context)) { // if the alarm has run this day
        calendar.add(Calendar.DATE, 1); // schedule it to run again starting
                                        // tomorrow
    }

    long firstRunTime = calendar.getTimeInMillis();
    AlarmManager mgr = (AlarmManager) context
            .getSystemService(Context.ALARM_SERVICE);
    Intent notificationIntent = new Intent(context, ReminderAlarm.class);
    PendingIntent pi = PendingIntent.getActivity(context, 0,
            notificationIntent, 0);
    mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstRunTime,
            AlarmManager.INTERVAL_DAY, pi);

    ComponentName receiver = new ComponentName(context, BootReceiver.class);
    PackageManager pm = context.getPackageManager();

    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);
}

Класс BootReceiver

public void onReceive(Context context, Intent i) {
    if (i.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
        Recurring.scheduleAlarms(context);
    }
}

Класс ReminderAlarm В основном для этого класса он просто захватывает переменную, переданную из класса Recurring, и выполняет вставку БД. Я вставил несколько Toast.makeText, чтобы проверить, извлекает ли он данные, но не повезло, протестировав их.

public class ReminderAlarm extends BroadcastReceiver {
private NotificationManager mNotificationManager;
private Notification notification;

@Override
public void onReceive(Context context, Intent intent) {
    String recurID = null;
    String recurStartDate = null;
    String currentDate = null;
    String description = null;
    String type = null;
    String amount = null;
    String categoryName = null;
    String frequencyStr = null;
    String nextPaymentDate = null;
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");

    DatabaseAdapter mDbHelper = new DatabaseAdapter(context);
    mDbHelper.createDatabase();
    mDbHelper.open();
    RecurringController rc = new RecurringController(mDbHelper.open());
    ArrayList<RecurringModel> recur_list = rc.getAllRecurring();

    // THIS PART TO GET DATA FROM DATABASE
    for (int i = 0; i < recur_list.size(); i++) {
        recurID = recur_list.get(i).getRecurringID();
        recurStartDate = recur_list.get(i).getRecurringStartDate();
        currentDate = dateFormat.format(new Date());
        description = recur_list.get(i).getRecurringDesc();
        type = recur_list.get(i).getRecurringType();
        amount = Float.toString(recur_list.get(i).getRecurringAmount());
        categoryName = recur_list.get(i).getCategoryID();
        frequencyStr = recur_list.get(i).getFrequency();

        Toast.makeText(context,
                    description, Toast.LENGTH_LONG)
                    .show();
        Toast.makeText(context,
                    recurStartDate Toast.LENGTH_LONG)
                    .show();

        Calendar cal = Calendar.getInstance();
        try {
            cal.setTime(dateFormat.parse(recurStartDate));
            if (frequencyStr.equals("Daily")) {
                cal.add(Calendar.DAY_OF_MONTH, 1);
                nextPaymentDate = dateFormat.format(cal.getTimeInMillis());
                cal.add(Calendar.DAY_OF_MONTH, -1);
            } else if (frequencyStr.equals("Weekly")) {
                cal.add(Calendar.WEEK_OF_YEAR, 1);
                nextPaymentDate = dateFormat.format(cal.getTimeInMillis());
                cal.add(Calendar.WEEK_OF_YEAR, -1);
            } else if (frequencyStr.equals("Monthly")) {
                cal.add(Calendar.MONTH, 1);
                nextPaymentDate = dateFormat.format(cal.getTimeInMillis());
                cal.add(Calendar.MONTH, -1);
            } else if (frequencyStr.equals("Yearly")) {
                cal.add(Calendar.YEAR, 1);
                nextPaymentDate = dateFormat.format(cal.getTimeInMillis());
                cal.add(Calendar.YEAR, -1);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }

        // If dates match then execute the SQL statements
        if (currentDate.equals(nextPaymentDate)) {
            // mDbHelper.createDatabase();
            // mDbHelper.open();
            TransactionRecModel trm = new TransactionRecModel();
            CategoryController cc = new CategoryController(mDbHelper.open());

            trm.setDate(currentDate);
            trm.setTransDescription(description);
            trm.setType(type);
            trm.setAmount(Float.parseFloat(amount));

            // Get the categoryID based on categoryName
            String catID = cc.getCatIDByName(categoryName);
            trm.setCategory(catID);

            // Check if the recurring record exists before insert new
            // transaction record
            boolean recurExist = rc.checkRecurExist(recurStartDate,
                    description, catID);
            if (recurExist == true) {
                TransactionRecController trc = new TransactionRecController(
                        mDbHelper.open());
                // Check if the transaction record exists to prevent
                // duplication
                boolean moveNext = trc.checkTransExist(trm);
                if (moveNext == false) {

                    if (trc.addTransactionRec(trm)) {
                        // Update recurring start date after insertion of
                        // transaction
                        RecurringModel rm = new RecurringModel();
                        rm.setRecurringID(recurID);
                        rm.setRecurringStartDate(currentDate);

                        if (rc.updateRecurringDate(rm)) {
                            mNotificationManager = (NotificationManager) context
                                    .getSystemService(Context.NOTIFICATION_SERVICE);
                            PendingIntent contentIntent = PendingIntent
                                    .getActivity(
                                            context,
                                            Integer.parseInt(intent
                                                    .getExtras()
                                                    .get("NotifyCount")
                                                    .toString()),
                                            new Intent(), 0);
                            notification = new Notification(
                                    R.drawable.ic_launcher, "Notification",
                                    System.currentTimeMillis());
                            notification.setLatestEventInfo(context,
                                    description, nextPaymentDate,
                                    contentIntent);
                            mNotificationManager
                                    .notify(Integer.parseInt(intent
                                            .getExtras().get("NotifyCount")
                                            .toString()), notification);
                            mDbHelper.close();
                        }
                    }
                }
            }
            mDbHelper.close();
        }
    }
    mDbHelper.close();
    Recurring.updateAlarmLastRun(context);
}
}

Я добавил эту часть кодов в ту часть, которую вы предложили запланировать для вызова будильника в классе BootReceiver. Затем из класса BootReceiver я перезвоню в класс Recurring и класс Alarm Reminder:

ComponentName receiver = new ComponentName(context, BootReceiver.class);
    PackageManager pm = context.getPackageManager();

    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);

1 ответ

Проблема в calendar.getTimeInMillis() в

mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
            calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);

Второй аргумент setInexactRepeating цитируя документ

triggerAtMillis время в миллисекундах, в течение которого будильник должен сначала сработать, используя соответствующие часы (в зависимости от типа будильника). Это неточно: сигнал тревоги не сработает до этого времени, но может быть задержка почти на весь интервал тревоги до первого вызова тревоги.

Это означает, что он будет запущен в первый раз приблизительно через одну минуту после того, как вы

calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0 );
calendar.set(Calendar.MINUTE, 1);

Если вы не хотите, чтобы первый запуск будильника был на следующий день, сделайте calendar.add(Calendar. DATE, 1);`

Что касается того, чтобы он перестал работать, вы перезагрузили устройство? AlarmCalendar не сохраняется до перезагрузки устройства, вы можете зарегистрировать BroadcastReceiver получить BOOT_COMPLETED событие и зарегистрируйте тревогу снова. Проверьте , сохраняется ли Alarm Manager даже после перезагрузки?

Обновление: как вы и просили, вам нужна помощь после просмотра кода.

В вашем BOOT_COMPLETED Классприемника:

public void onReceive(Context context, Intent i) {
    if (i.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
        ReminderAlarm.scheduleAlarms(this);
    }
}

В вашем классе ReminderAlarm

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recurring);

if(!alarmInitialized(this) { 
    scheduleAlarms(this); 
}

}

public static void scheduleAlarms(Context context) {

    Calendar calendar = Calendar.getInstance();

    if(hasRunnedToday(context)) {       //if the alarm has run this day
        calendar.add(Calendar.DATE, 1); //schedule it to run again starting tomorrow
    }

    long firstRunTime = calendar.getTimeInMillis();

    AlarmManager mgr = (AlarmManager) context
            .getSystemService(Context.ALARM_SERVICE);
    Intent notificationIntent = new Intent(context, ReminderAlarm.class);
    PendingIntent pi = PendingIntent.getActivity(context, 0,
            notificationIntent, 0);

    mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
            firstRunTime, AlarmManager.INTERVAL_DAY, pi);
}

public static boolean alarmInitialized(Context context) {
    SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE);

    long alarmLastRun = preferences.getLong("AlarmLastRun", -1);


    return alarmLastRun != -1;

}

public static void updateAlarmLastRun(Context context) {
    SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE);


    preferences.edit()
            .putLong("AlarmLastRun", new Date().getTime())
        .apply();
}

public static boolean hasRunnedToday(Context context) {
    SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE);

    long alarmLastRun = preferences.getLong("AlarmLastRun", -1);

    if(alarmLastRun == -1) {
        return false;
    }

    //check by comparing day, month and year
    Date now = new Date();
    Date lastRun = new Date(alarmLastRun);


    return now.getTime() - lastRun.getTime() < TimeUnit.DAYS.toMillis(1);
}

Каждый раз, когда срабатывает сигнализация класса Reminder, вы должны позвонить updateAlarmLastRun чтобы обновить последний раз, когда сработал будильник, это необходимо, потому что будильник может быть запланирован на день, и пользователь перезагружает устройство до срабатывания будильника, в этом случае мы не хотим использовать calendar.add(Calendar.DATE, 1); так как это пропустит день.

На ваше Manifest.xml

<receiver android:name=".BootReceiver" android:enabled="true" android:exported="false" android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
     <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
    </receiver>

Заметки:

  1. Ты не должен делать context = this если context является полем класса, так как объект содержит ссылку на свое поле context а также context поле содержит ссылку на объект, который будет протекать
  2. Ваш Receiver "onReceive" не имеет дополнительных функций, которые, как вы предполагали, имеют, например, "messagesCount" при получении системой после завершения загрузки вашего устройства.
  3. Как только ваш будильник запускает звонок updateAlarmLastRun

Надеюсь, что это поможет

Другие вопросы по тегам