android - AlarmManager 只能在不久的将来工作

标签 android xamarin alarmmanager xamarin.forms

我正在开发适用于 Android、iOS 和 Windows Phone 的 Xamarin 应用程序。此应用程序应在指定时间显示本地通知。对于 Android,我使用的是 AlamManager。通知适用于 iOS、WinPhone 和 Android 模拟器。在我的设备 (Samsung Galaxy S2) 上,只有近期(1 分钟、5 分钟、20 分钟)的通知有效。大约 45 分钟或更长时间后的通知不会出现。大约 30 分钟后的通知有时会出现,有时不会。通知是在广播接收器中发出的。我的代码或 alarmManager 有问题吗?找不到任何东西。感谢您的帮助。

这里设置了alarmManager:

public class NotificationService : NotificationServiceBase
{
    private readonly AlarmManager _alarmManager;
    private readonly long _dayInMilliseconds = AlarmManager.IntervalDay;
    private PendingIntent _currentPendingIntent;

    public NotificationService()
    {
        _alarmManager = (AlarmManager) Forms.Context.GetSystemService(Context.AlarmService);
    }

    public override void CancelNotification()
    {
        _alarmManager.Cancel(_currentPendingIntent);
    }

    protected override void ChangeNotificationTime(TaskEntity task)
    {
        var settings = _settingsBusinessLayer.GetSettings();
        NotificationSetup(settings, task);
    }

    protected override async void ChangeNotificationSettings(SettingsEntity settings)
    {
        if (!settings.IsReminderOn)
        {
            CancelNotification();
            return;
        }

        var task = await _taskBusinessLayer.GetTaskForCurrentMonthAsync(true, true);
        NotificationSetup(settings, task);
    }

    private void NotificationSetup(SettingsEntity settings, TaskEntity task)
    {
        _currentPendingIntent = GetPendingIntent();
        _alarmManager.Cancel(_currentPendingIntent);

        if (settings.ReminderRepetitive == ReminderRepetitive.Daily)
        {
            SetDailyAlarm(settings);
        }
        else
        {
            SetSingleAlarm(settings, task);
        }
    }

    private void SetDailyAlarm(SettingsEntity settings)
    {
        long alarmTimeInMilliseconds;

        if (settings.RemindOn < DateTime.Now.TimeOfDay)
        {
            alarmTimeInMilliseconds = (long) CalculateAlarmTimeFromNow
                (DateTime.Now.AddDays(1), 0, settings.RemindOn).TotalMilliseconds;
        }
        else
        {
            alarmTimeInMilliseconds = (long) CalculateAlarmTimeFromNow
                (DateTime.Now, 0, settings.RemindOn).TotalMilliseconds;
        }

        var alarmTime = SystemClock.ElapsedRealtime() + alarmTimeInMilliseconds;
        _alarmManager.SetRepeating(AlarmType.ElapsedRealtime, alarmTime, _dayInMilliseconds, _currentPendingIntent);
    }

    private void SetSingleAlarm(SettingsEntity settings, TaskEntity task)
    {
        try
        {
            var alarmTimeInMilliseconds = (long) CalculateAlarmTimeFromNow
                (task.DueDate, Convert.ToUInt32(settings.RemindDaysBefore), settings.RemindOn).TotalMilliseconds;
            var alarmTime = SystemClock.ElapsedRealtime() + alarmTimeInMilliseconds;
            _alarmManager.Set(AlarmType.ElapsedRealtime, alarmTime, _currentPendingIntent);
        }
        catch (AlarmTimeIsInPastException)
        {
        }
    }

    private PendingIntent GetPendingIntent()
    {
        var alarmIntent = new Intent(Forms.Context, typeof (NotificationReceiver));
        return PendingIntent.GetBroadcast(Forms.Context, 0, alarmIntent,
            PendingIntentFlags.UpdateCurrent);
    }
}

广播接收器,发出通知的地方。

[BroadcastReceiver]
public class NotificationReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        var taskBusinessLayer = DependencyInjection.Container.Resolve<ITaskBusinessLayer>();
        var task = taskBusinessLayer.GetTaskForCurrentMonthAsync(true, true).Result;
        var message = NotificationServiceBase.CreateNotificationMessageRemainingTime(task);
        var title = AppResources.NotificationTitle;
        var notIntent = new Intent(context, typeof (MainActivity));
        var contentIntent = PendingIntent.GetActivity(context, 0, notIntent, PendingIntentFlags.CancelCurrent);

        var builder = new Notification.Builder(context)
            .SetContentIntent(contentIntent)
            .SetContentTitle(title)
            .SetContentText(message)
            .SetSmallIcon(Resource.Drawable.icon)
            .SetDefaults(NotificationDefaults.Sound | NotificationDefaults.Vibrate)
            .SetPriority((int) NotificationPriority.Max)
            .SetAutoCancel(true)
            .SetWhen(JavaSystem.CurrentTimeMillis());

        var notification = builder.Build();
        var notificationManager = NotificationManager.FromContext(context);

        const int notificationId = 0;
        notificationManager.Notify(notificationId, notification);
    }

}

最佳答案

从 KITKAT 开始的警报传递不准确。所以你可能需要改变你的 SetSingleAlarm 方法:

_alarmManager.Set(AlarmType.ElapsedRealtime, alarmTime, _currentPendingIntent);

为此:

if (Build.VERSION.SdkInt < BuildVersionCodes.Kitkat)
{
    _alarmManager.Set(AlarmType.ElapsedRealtime, alarmTime, _currentPendingIntent);
}
else
{
    _alarmManager.SetExact(AlarmType.ElapsedRealtime, alarmTime, _currentPendingIntent);
}

关于android - AlarmManager 只能在不久的将来工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30870914/

相关文章:

javascript - Phonegap 相机错误

android - 如何在应用程序图标或小部件中显示徽章计数

Android StateListDrawable 在 MultiTouch 之后保持按下状态

android - AlarmManager 在应用程序销毁时被杀死

java - Android 每 30 天发送一次通知?

android - 每天在特定时间运行代码 - AlarmManager

android - 将 JavaScript 接口(interface)添加到浏览器

android - 分配 App.MainPage 时 MasterDetailPage 上缺少菜单按钮

c# - 如何从另一个类中删除 ListView 项

android - 在xamarin android中实现admob会抛出Java.Lang.RuntimeException