简体   繁体   中英

Repeating notifications issue

I'm struggling with notifications.

I want to randomly select text to display in the notification (using random() method on the array of String objects from separate object file NotificationData where I only had one immutable variable called notificationData ), which should appear once a day at a specific time (but for now, for the purpose of the test, I wrote in the code to appear every hour). I'm using AlarmManager for scheduling. The first thing is the notifications does not appear at the specified hour when the app is not currently working (or during the device sleep mode), but after launching the app. And second thing is that after launching the app, notifications appear almost one by one within few seconds. I don't really understand why it happens in this way. It's quite strange for me.

Here's the NotificationUtils class, where I create my notification and put one String from Array inside setContentText() method:

package com.example.quit.notification

class NotificationUtils(context: Context) {
    private var mContext = context
    private lateinit var notificationBuilder: NotificationCompat.Builder
    val notificationManager = NotificationManagerCompat.from(mContext)
    private val CHANNEL_ID = "Notification_Channel"

    init {
        createNotificationChannel()
        initNotificationBuilder()
    }

    fun launchNotification() {
        with(NotificationManagerCompat.from(mContext)) {
            notificationManager.notify(0, notificationBuilder.build())
        }
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val name = "Rady"
            val description = "Codzienne rady dla zdrowiejących osób uzależnionych"
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
                this.description = description
            }

            val notificationManager: NotificationManager = mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }
    }

    private fun initNotificationBuilder() {
        val sampleIntent = Intent(mContext, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        }
        val pendingIntent: PendingIntent = PendingIntent.getActivity(mContext, 0, sampleIntent, 0)

        val data = NotificationData.notificationData.random()

        notificationBuilder = NotificationCompat.Builder(mContext, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_support)
            .setContentTitle("Rada na dziś")
            .setContentText(data)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
    }
}

Second class, where I create repeating alarm:

package com.example.quit.notification

@SuppressLint("UnspecifiedImmutableFlag")
class AlarmUtils(context: Context) {
    private var mContext = context
    private var alarmManager: AlarmManager? = null
    private var alarmIntent: PendingIntent

    init {
        alarmManager = mContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        alarmIntent = Intent(mContext, AlarmReceiver::class.java).let { mIntent ->
            PendingIntent.getBroadcast(mContext, 100, mIntent, PendingIntent.FLAG_UPDATE_CURRENT)
        }
    }

    fun initRepeatingAlarm(calendar: Calendar) {
        calendar.apply {
            set(Calendar.HOUR_OF_DAY, 20)
            set(Calendar.MINUTE, 30)
            set(Calendar.SECOND, 0)
        }

        alarmManager?.set(
            AlarmManager.RTC_WAKEUP,
            calendar.timeInMillis,
            alarmIntent
        )
    }
}

Here's my AlarmReceiver , where I set next alarm after one hour in this case (:

package com.example.quit.notification

class AlarmReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val notificationUtils = NotificationUtils(context!!)
        notificationUtils.launchNotification()

        val calendar = Calendar.getInstance()
        calendar.add(Calendar.HOUR_OF_DAY, 1)
        val alarmUtils = AlarmUtils(context)
        alarmUtils.initRepeatingAlarm(calendar)
    }
}

In AndroidManifest.xml file I only added one line intag:

<receiver android:name=".notification.AlarmReceiver" />

And the last thing - in MainActivity class I put those three lines just after setContentView() method:

val calendar = Calendar.getInstance()
val alarmUtils = AlarmUtils(this)
alarmUtils.initRepeatingAlarm(calendar)

I'll be very grateful for any help and explanations.

It is obvious why your notifications appear immediately. In AlarmReceiver you do this:

    val calendar = Calendar.getInstance()
    calendar.add(Calendar.HOUR_OF_DAY, 1)
    val alarmUtils = AlarmUtils(context)
    alarmUtils.initRepeatingAlarm(calendar)

You want to take the current time, add one hour and schedule an alarm at that time (1 hour in the future). However, look at what initRepeatingAlarm() is doing:

    calendar.apply {
        set(Calendar.HOUR_OF_DAY, 20)
        set(Calendar.MINUTE, 30)
        set(Calendar.SECOND, 0)
    }

in initRepeatingAlarm() you are setting the hour, minute and seconds to a fixed value (which is the time that the alarm originally went off). You are overwriting the time that was set in the Calendar that was passed in. In this case, when the alarm is set, the time is in the past so the alarm triggers immediately.


Regarding why the alarms do not work when the device is sleeping, the call to AlarmManager.set() is not considered "exact" and the system may delay the alarm to ensure that the device is not constantly awakened (preservation of battery). See this explanation found in the documentation.

If you want the alarm to go off at exactly this time, you need to use a different method, such as setExact() , and you will need to declare an additional permission SCHEDULE_EXACT_ALARM (if you target API level 31 or higher)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM