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

问题描述 投票:3回答:3

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

如果我尝试10秒的代码,它的工作原理。当我尝试5天时,没有任何反应。

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

火灾日期是正确的,因为我将它们存储在数据库中,我已经证明了它。

表现:

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

NotificationScheduler:

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
    }
}
android android-notifications android-alarms android-broadcastreceiver
3个回答
2
投票

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

WorkManager与Android Jetpack / Architecture Components一起推出。

Solution

  • 首先为WorkManager添加依赖项,您可以找到最新版本here
  • 创建一个Worker class,以及在doWork()中显示通知的代码。
  • 在您的应用开始时安排此工作,也检查是否已安排。为了方便起见,我已经在下面的类中创建了一个名为isWorkScheduled()的方法。
  • 您可以通过setInputData()向您的任务发送其他数据(如putExtra())。
  • 在第一个活动onCreate()或Application类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.)
    }
}

我建议你只使用WorkManger,因为我早些时候用JobSchedulerEvernoteJobsAlarmManagerJobServiceWorkManager创建了一个样本。其中我开始每个15分钟的周期性任务。并在调用时将每个日志写入单独的文件中。

这个测试的结论就是这样。 WorkManagerEvernoteJobs是最有效率的工作。现在因为EvernoteJobs将使用下一版本的WorkManager。所以我想出了WorkManager。

Update

安排定期任务的最短时间是15分钟,所以请记住。您可以在documentation.中阅读更多内容


0
投票

该设备是否在五天期间关闭?根据文件:

默认情况下,设备关闭时会取消所有警报。为防止这种情况发生,您可以将应用程序设计为在用户重新启动设备时自动重新启动重复警报。这可确保AlarmManager将继续执行其任务,而无需用户手动重新启动警报。 Set an alarm when the device restarts.

想到的另一件事是您可能想要使用AlarmManager.RCT_WAKEUP而不是AlarmManager.RTC来确保设备清醒以传递意图并创建和发送您的通知。

尝试:

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

0
投票

最有可能的情况是,当您的设备进入打盹模式并且警报管理器未触发您的预定警报时尝试使用(这是Java代码):

AlarmManager alarmManager = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
    }
    else{
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
        }
    }

看看setExactAndAllowWhileIdle

© www.soinside.com 2019 - 2024. All rights reserved.