Пропущенные уведомления с помощью AlarmManager

#android #kotlin #android-notifications #alarmmanager

#Android #kotlin #android-уведомления #AlarmManager

Вопрос:

Я сталкиваюсь с проблемой при планировании нескольких (до 14) уведомлений с помощью AlarmManager. Проблема в том, что уведомления случайным образом отсутствуют (особенно когда отладочный кабель не подключен). Например, запускаются первые три уведомления, и после этих уведомлений ни одно из запланированных уведомлений больше не запускается, пока вы не измените расписание уведомлений. Кажется, это из-за количества уведомлений, но я не уверен на 100%.

Ниже вы можете найти мои функции для планирования уведомлений (уведомления о тревоге и перед сном);

 private fun createNotificationChannel(name: String, descriptionText: String, id: String, setSound:Boolean)
  {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
      val importance = NotificationManager.IMPORTANCE_DEFAULT
      val channel = NotificationChannel(id, name, importance).apply {
        description = descriptionText
      }
      val audioAttributes = AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
        .setUsage(AudioAttributes.USAGE_NOTIFICATION)
        .build()
      if (setSound)
      {
        channel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE   "://"   m_context.packageName   "/"   m_ringtone), audioAttributes)
      }
      (m_context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel)
    }
  }

  private fun createBedTimeNotificationChannel()
  {
    createNotificationChannel(BEDTIME_NOTIFICATION_CHANNEL_NAME, BEDTIME_NOTIFICATION_CHANNEL_DESCRIPTION, BEDTIME_NOTIFICATION_CHANNEL, false)
  }

  private fun createWakeUpNotificationChannel()
  {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
      for (channel in (m_context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).notificationChannels)
      {
        if (channel.id.contains(WAKE_UP_ALARM_NOTIFICATION_CHANNEL))
        {
          (m_context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).deleteNotificationChannel(channel.id)
        }
      }
      m_randomNumber = Random().nextLong()
      createNotificationChannel(WAKE_UP_NOTIFICATION_CHANNEL_NAME, WAKE_UP_NOTIFICATION_CHANNEL_DESCRIPTION, WAKE_UP_ALARM_NOTIFICATION_CHANNEL   m_randomNumber, true)
    }
  }

  fun configureAlarmNotification(ringtone: Int, alarmTime: Int, snooze: Boolean, days: BooleanArray)
  {
    m_ringtone = ringtone
    createWakeUpNotificationChannel()
    for ((index, alarmOn) in days.withIndex())
    {
      if (alarmOn)
      {
        val builder = getWakeUpAlarmBuilder()

        val intent = Intent(m_context, CMainActivity::class.java)
        val activity = PendingIntent.getActivity(m_context, WAKE_UP_NOTIFICATION_ID_START   index   1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        builder.setContentIntent(activity)

        if (snooze)
        {
          val snoozeIntent = Intent(m_context, CSleepPlannerService::class.java).apply {
            putExtra(ACTION, ACTION_SNOOZE)
            putExtra(NOTIFICATION_ID, WAKE_UP_NOTIFICATION_ID_START   index   1)
            putExtra(NOTIFICATION, builder.build())
          }

          val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(m_context, SNOOZE_PRESSED_NOTIFICATION_ID   index   1, snoozeIntent, 0)
          builder.addAction(R.drawable.alarm_bel_icon, m_context.getString(R.string.snooze), snoozePendingIntent)
        }

        val notification = builder.build()
        val calendar = Calendar.getInstance()
        val currentTimeInMillis = calendar.timeInMillis

        calendar[Calendar.DAY_OF_WEEK] = convertWeekday(index)
        calendar[Calendar.HOUR_OF_DAY] = alarmTime / 60
        calendar[Calendar.MINUTE] = alarmTime % 60
        calendar[Calendar.SECOND] = 0

        if (calendar.timeInMillis <= currentTimeInMillis)
        {
          calendar.timeInMillis  = NUMBER_OF_MILLIS_IN_WEEK
        }

        val pendingIntent = getPendingIntent(calendar.timeInMillis, WAKE_UP_NOTIFICATION_ID_START   index   1, notification, ACTION_NOTIFICATION, PendingIntent.FLAG_UPDATE_CURRENT)
        (m_context.getSystemService(ALARM_SERVICE) as AlarmManager).setExact(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
      }
    }

    val calendar = Calendar.getInstance()
    m_alarmWithSoundEnabledWithinADay.postValue((m_preferences.isAlarmWithSoundEnabled() amp;amp; isAlarmEnabled(calendar[Calendar.HOUR_OF_DAY] * 60   calendar[Calendar.MINUTE], m_preferences.getAlarmTime(), calendar[Calendar.DAY_OF_WEEK])))
  }

  fun configureBedTimeNotification(bedTime: Int, bedTimeSetting: Int, days: BooleanArray)
  {
    for ((index, alarmOn) in days.withIndex())
    {
      if (alarmOn)
      {
          val builder = NotificationCompat.Builder(m_context, BEDTIME_NOTIFICATION_CHANNEL).apply {
            setContentTitle(m_context.getString(R.string.bedtime_notification_tile))
            when (BedTimeNotificationSetting_e.fromInt(bedTimeSetting))
            {
              BedTimeNotificationSetting_e.AT_BED_TIME -> setContentText(m_context.getString(R.string.bedtime_notification_at_bedtime))
              BedTimeNotificationSetting_e.TEN_MINUTES_BEFORE -> setContentText(m_context.getString(
                  R.string.bedtime_notification_description_ten
                ))
              BedTimeNotificationSetting_e.THIRTY_MINUTES_BEFORE -> setContentText(m_context.getString(R.string.bedtime_notification_description_thirty))
              BedTimeNotificationSetting_e.FORTYFIVE_MINUTES_BEFORE -> setContentText(m_context.getString(R.string.bedtime_notification_description_fortyfive))
              BedTimeNotificationSetting_e.SIXTY_MINUTES_BEFORE -> setContentText(m_context.getString(R.string.bedtime_notification_description_sixty))
            }
            setAutoCancel(true)
            setSmallIcon(R.drawable.alarm_icon)
            priority = NotificationCompat.PRIORITY_HIGH
          }

        val intent = Intent(m_context, CMainActivity::class.java)
        val activity = PendingIntent.getActivity(m_context, BEDTIME_NOTIFICATION_ID_START   index   1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        builder.setContentIntent(activity)
        val notification = builder.build()

        val calendar = Calendar.getInstance()
        val currentTimeInMillis = calendar.timeInMillis

        calendar[Calendar.DAY_OF_WEEK] = convertWeekday(index)
        calendar[Calendar.HOUR_OF_DAY] = bedTime / 60
        calendar[Calendar.MINUTE] = bedTime % 60
        calendar[Calendar.SECOND] = 0

        var newBedTime = calendar.timeInMillis - (bedTimeSetting * 60 * 1000)

        if (newBedTime <= currentTimeInMillis)
        {
          newBedTime  = NUMBER_OF_MILLIS_IN_WEEK
        }

        val pendingIntent = getPendingIntent(newBedTime, BEDTIME_NOTIFICATION_ID_START   index   1, notification, ACTION_NOTIFICATION, PendingIntent.FLAG_UPDATE_CURRENT)
        (m_context.getSystemService(ALARM_SERVICE) as AlarmManager).setExact(AlarmManager.RTC_WAKEUP, newBedTime, pendingIntent)
      }
    }
  }

  private fun getPendingIntent(calendarTime: Long = 0, notificationId: Int, notification: Notification? = null, action: String, flag: Int) : PendingIntent?
  {
    val notificationIntent = Intent(m_context, this::class.java)
    notificationIntent.putExtra(ACTION, action)
    notificationIntent.putExtra(NOTIFICATION_ID, notificationId)
    notificationIntent.putExtra(NOTIFICATION, notification)
    notificationIntent.putExtra(ALARM_TIME, calendarTime)
    return PendingIntent.getBroadcast(m_context, notificationId, notificationIntent, flag)
  }

 

Что может быть причиной этого?

Ответ №1:

Трудно точно знать, что может быть не так. В зависимости от версии системы Android может решить подождать / отложить / группировать уведомления. Оставшийся заряд батареи также влияет на решение показать уведомление.

Я вижу, что вы используете setPriority в конструкторе уведомлений HIGH значение. Это должно работать для Android <api 26. Для более новых версий будет setImportance учитываться канал уведомлений

см. https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder?hl=en#setPriority(int)

  1. При создании канала попробуйте использовать High importance

val importance = NotificationManager.IMPORTANCE_HIGH // отредактируйте свой код следующим образом в createNotificationChannel, который вы используете в настоящее время DEFAULT

  1. убедитесь, что в телефоне, который вы используете для тестирования, нет такой опции, как экономия заряда батареи или что-то еще.

Ответ №2:

Я исправил проблему с настройкой уведомлений о пробуждении с помощью функции setAlarmClock из AlarmManager.