android - 通过 AlarmManager 和 BroadcastReceiver 发送通知不起作用?

标签 android android-notifications android-alarms android-broadcastreceiver

我提前 5 天安排了一个通知,所以我使用 AlarmManager 创建了一个警报,它会触发一个 PendingIntent,它会触发我的 BroadcastReceiver。

如果我尝试该代码 10 秒钟,它就会起作用。当我尝试 5 天时,没有任何反应。

NotificationScheduler 类是用于设置和更新警报的辅助类。

开火日期是正确的,因为我将它们存储在数据库中,并且我已经对其进行了校对。

list :

<receiver android:name=".reminder.ReminderReceiver" />

通知调度器:

class NotificationScheduler {

    companion object {

        const val NOTIFICATION_EXTRA_CLAIM_ID = "notification_extra_bookentry_id"

        const val INTENT_ACTION_REMINDER = "at.guger.moneybook.reminder"

        fun setReminder(context: Context, bookEntryId: Long, fireDate: Date? = null) {
            val mCalendar = Calendar.getInstance()

            val lFireDate = if (fireDate == null) {
                mCalendar.timeInMillis += 5 * 24 * 3600 * 1000
                mCalendar.set(Calendar.HOUR_OF_DAY, 12)

                mCalendar.time
            } else {
                fireDate
            }

            create(context, bookEntryId, lFireDate.time)

            AppDatabase.getInstance(context).reminderDao().insert(Reminder(bookEntryId, lFireDate))
        }

        fun updateReminder(context: Context, bookEntryId: Long) {
            cancel(context, bookEntryId)

            val mCalendar = Calendar.getInstance()
            mCalendar.timeInMillis += 5 * 24 * 3600 * 1000
            mCalendar.set(Calendar.HOUR_OF_DAY, 12)

            create(context, bookEntryId, mCalendar.timeInMillis)

            AppDatabase.getInstance(context).reminderDao().update(Reminder(bookEntryId, mCalendar.time))
        }

        fun cancelReminder(context: Context, bookEntryId: Long) {
            cancel(context, bookEntryId)

            AppDatabase.getInstance(context).reminderDao().delete(Reminder(bookEntryId))
        }

        private fun create(context: Context, bookEntryId: Long, fireDate: Long) {
            val mAlarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

            val mComponentName = ComponentName(context, ReminderReceiver::class.java)
            context.packageManager.setComponentEnabledSetting(mComponentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP)

            val mIntent = Intent(context, ReminderReceiver::class.java)
            mIntent.action = INTENT_ACTION_REMINDER
            mIntent.putExtra(NOTIFICATION_EXTRA_CLAIM_ID, bookEntryId)

            val mPendingIntent = PendingIntent.getBroadcast(context, bookEntryId.toInt(), mIntent, PendingIntent.FLAG_UPDATE_CURRENT)

            if (Utils.isKitKat()) {
                mAlarmManager.setWindow(AlarmManager.RTC, fireDate, AlarmManager.INTERVAL_HOUR, mPendingIntent)
            } else {
                mAlarmManager.set(AlarmManager.RTC, fireDate, mPendingIntent)
            }
        }

        private fun cancel(context: Context, bookEntryId: Long) {
            val mAlarmManager: AlarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

            val mComponentName = ComponentName(context, ReminderReceiver::class.java)
            context.packageManager.setComponentEnabledSetting(mComponentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP)

            val mIntent = Intent(context, ReminderReceiver::class.java)
            mIntent.putExtra(NOTIFICATION_EXTRA_CLAIM_ID, bookEntryId)

            val mPendingIntent = PendingIntent.getBroadcast(context, bookEntryId.toInt(), mIntent, PendingIntent.FLAG_UPDATE_CURRENT)

            mAlarmManager.cancel(mPendingIntent)
            mPendingIntent.cancel()
        }
    }
}

广播接收者:

class ReminderReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context?, intent: Intent?) {
        if (context != null && intent != null) {
            when (intent.action) {
                NotificationScheduler.INTENT_ACTION_REMINDER -> {
                    val mPowerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
                    val mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this::class.simpleName)

                    mWakeLock.acquire(WAKELOCK_TIME)

                    val iClaimEntryId = intent.getLongExtra(NotificationScheduler.NOTIFICATION_EXTRA_CLAIM_ID, -1)

                    showNotification(context, iClaimEntryId)
                    AppDatabase.getInstance(context).reminderDao().delete(Reminder(iClaimEntryId))

                    mWakeLock.release()
                }
            }
        }
    }

    private fun showNotification(context: Context, claimEntryId: Long) {
        val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val nBuilder: Notification.Builder

        if (Utils.isOreo()) {
            val mNotificationChannel = NotificationChannel(NOTIFICATIONCHANNEL_CLAIMREMINDERID, context.getString(R.string.notificationchannel_claimreminder_title), NotificationManager.IMPORTANCE_DEFAULT)
            mNotificationChannel.description = context.getString(R.string.notificationchannel_claimreminder_description)

            mNotificationManager.createNotificationChannel(mNotificationChannel)

            nBuilder = Notification.Builder(context, NOTIFICATIONCHANNEL_CLAIMREMINDERID)
        } else {
            nBuilder = Notification.Builder(context)
        }

        val mClaimEntry: BookEntry = AppDatabase.getInstance(context).bookEntryDao().get(claimEntryId)

        val mCurrencyFormatter = DecimalFormat.getCurrencyInstance(Preferences.getInstance(context).currency.locale)

        nBuilder.setSmallIcon(R.drawable.ic_money)
        nBuilder.setContentTitle(context.getString(R.string.notification_claimreminder_title, mCurrencyFormatter.format(mClaimEntry.dValue)))
        val sContacts = mClaimEntry.getContacts(context).joinToString().takeIf { it.isNotEmpty() }
                ?: "-"
        nBuilder.setContentText(context.getString(R.string.notification_claimreminder_content, sContacts))
        nBuilder.setContentIntent(PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT))
        nBuilder.setAutoCancel(true)

        mNotificationManager.notify(mClaimEntry.lId!!.toInt(), nBuilder.build())
    }

    companion object {
        const val NOTIFICATIONCHANNEL_CLAIMREMINDERID = "notification_channel_claimreminder"

        const val WAKELOCK_TIME: Long = 1000
    }
}

最佳答案

我在使用 AlarmManager 时遇到了问题,所以我现在正在使用 WorkManager。

WorkManager是随 Android Jetpack/Architecture Components 引入的。

解决方案

  • 首先添加WorkManager的依赖,可以找到最新版本here .
  • 创建一个Worker 类,以及在doWork() 中显示通知的代码。

  • 在您的应用启动时安排这项工作,同时检查是否尚未安排。为了方便起见,我已经在下面的类中创建了一个名为 isWorkScheduled() 的方法。

  • 您可以通过 setInputData() 向您的任务发送额外的数据(如 putExtra()) .

  • 在第一个 Activity onCreate() 或应用程序类 onCreate 中安排您的一次性任务。

例子

public static final String TAG_WORK = "myTag";
if(!MyWork.isWorkScheduled(TAG_WORK))
    MyWork.scheduleOneTimeTask(TAG_WORK, 5, TimeUnit.DAYS)

MyWork.java

public class MyWork extends Worker {
    public static void scheduleOneTimeTask(String tag, long duration, TimeUnit timeUnit) {
        OneTimeWorkRequest compressionWork =
                new OneTimeWorkRequest.Builder(MyWork.class).setInitialDelay(duration, timeUnit).addTag(tag)
                        .build();
        WorkManager instance = WorkManager.getInstance();
        if (instance != null) {
            instance.enqueue(compressionWork);
        }
    }

    private boolean isWorkScheduled(String tag) {
        WorkManager instance = WorkManager.getInstance();
        if (instance == null) return false;
        LiveData<List<WorkStatus>> statuses = instance.getStatusesByTag(tag);
        if (statuses.getValue() == null) return false;
        boolean running = false;
        for (WorkStatus workStatus : statuses.getValue()) {
            running = workStatus.getState() == State.RUNNING | workStatus.getState() == State.ENQUEUED;
        }
        return running;
    }

    @NonNull
    @Override
    public Result doWork() {
        // show notification
        return Result.SUCCESS;
        // (Returning RETRY tells WorkManager to try this task again
        // later; FAILURE says not to try again.)
    }
}

I suggested you WorkManger only, because I created a sample earlier days with JobScheduler, EvernoteJobs, AlarmManager, JobService, and WorkManager. In which I started periodic task of 15 minutes with each of these. and wrote logs of each in separate file when invoked.

Conclusion of this test was that. WorkManager and EvernoteJobs were most efficient to do jobs. Now because EvernoteJobs will use WorkManager from next version. So I came up with WorkManager.

更新

调度周期性任务的最短时间为 15 分钟,因此请记住。您可以在 documentation. 中阅读更多内容

关于android - 通过 AlarmManager 和 BroadcastReceiver 发送通知不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52017035/

相关文章:

android - 通过警报管理器在特定时间创建通知

android - 取消从多任务面板中删除应用程序的通知

android - Unity3d : Android and iOS Push Notifications

安卓闹钟音量逐渐增大

java - WakefulBroadcastReceiver 无法解析为类型

android - 通知自定义声音在前台播放但在后台应用程序时不播放

android - 如果应用程序被卸载,应用程序通过警报管理器设置的警报会发生什么

android - 如何在android中使用Zxing

Android - ListView 和标签

android - 服务内的 BroadcastReceiver 未处理通知操作的广播