【问题标题】:How can I run a Task every Day at the same Time in Xamarin Forms Android?如何在 Xamarin Forms Android 中每天同时运行一个任务?
【发布时间】:2020-10-07 16:39:23
【问题描述】:

我是 Xamarin 和 Android 编程的新手。我目前正在尝试创建一个应用程序,它每晚在凌晨 1 点左右检查设备的位置。时间将使用 TimePicker 在设置页面中设置。我目前面临的唯一挑战是如何安排此任务,以便即使应用程序关闭或设备处于 Dooze 模式,它也能运行。目标平台是 Android 9(Pie)。

到目前为止,我创建了一个前台服务。该前台服务使用 SetRepeading 方法和模式 Rtc_Wakeup 设置 AlarmManager。但这并不像我希望的那样工作!问题是当应用程序设置为后台或关闭时,警报会被触发。但它应该只有在达到触发时间时才被触发。还是我搞错了?

你可以从我的Git Repository获取整个代码

实现这一目标的最佳方法是什么? 谢谢! :)

这是我目前尝试过的 :)

这是我的 ForegroundService 类:


using Android.App;
using Android.Content;
using Android.OS;
using AnwesenheitsApp.Droid.Alarm;

namespace AnwesenheitsApp.Droid
{
    [Service]
    class PositionServiceDroid : Service
    {
        private Logging.Logging _logger = new Logging.Logging();
        private static AlarmHandler alarm = new AlarmHandler();

        public override StartCommandResult OnStartCommand(Intent intent,
            StartCommandFlags flags, int startId)
        {
            int messageID = 90000;

            var notifMngr = new NotificationManagerDroid();
            Notification notification = notifMngr.ReturnNotification(
                "Positions Service", "Die überwachung der Position für die" +
                " automatische Prüfung der Anwesenheit läuft!");

            StartForeground(messageID, notification);

            alarm.SetAlarm();

            return StartCommandResult.Sticky;
        }

        public override bool StopService(Intent name)
        {
            alarm.UnsetAlarm();
            return base.StopService(name);
        }

        public override void OnDestroy()
        {
            alarm.UnsetAlarm();
            base.OnDestroy();
        }

        public override IBinder OnBind(Intent intent)
        {
            return null;
        }  
    }
}

这是我的 AlarmHandler 类:

using System;

using Android.App;
using Android.Content;
using Android.Runtime;

namespace AnwesenheitsApp.Droid.Alarm
{
    class AlarmHandler
    {
        public void SetAlarm()
        {
            var alarmIntent = new Intent(Application.Context, typeof(AlarmReciver));
            var pending = PendingIntent.GetBroadcast(Application.Context,
                0, alarmIntent, PendingIntentFlags.UpdateCurrent);
            var alarmManager = Application.Context.GetSystemService(Application.AlarmService)
                .JavaCast<AlarmManager>();

            //For Testing
            var now = DateTime.Now;

            var dt = new DateTime(now.Year, now.Month, now.Day,
                19, 5, 0, 0).Ticks / 10000;

            long millis = dt - now.Ticks / 10000;

            alarmManager.SetRepeating(AlarmType.RtcWakeup, millis,
                1000 * 60 * 60 * 4, pending);
        }

        public void UnsetAlarm()
        {
            var alarmIntent = new Intent(Application.Context, typeof(AlarmReciver));
            var pending = PendingIntent.GetBroadcast(Application.Context,
                0, alarmIntent, PendingIntentFlags.UpdateCurrent);
            var alarmManager = Application.Context.GetSystemService(Application.AlarmService)
                .JavaCast<AlarmManager>();

            alarmManager.Cancel(pending);
        }
    }
}

这是 BroadcastReceiver 类:

using System;
using System.Linq;
using AnwesenheitsApp.DbModels;
using Xamarin.Essentials;

using Android.Content;

namespace AnwesenheitsApp.Droid.Alarm
{
    [BroadcastReceiver]
    class AlarmReciver : BroadcastReceiver
    {
        private LocationData _data;
        private Logging.Logging _logger = new Logging.Logging();

        public override void OnReceive(Context context, Intent intent)
        {
            GetLocationData();
        }

        private void SaveDataToDb(LocationData data)
        {
            App.Database.SaveLocationDataToDbAsync(data);
        }

        private async void GetLocationData()
        {
            if (this._data == null)
                this._data = new LocationData();


            try
            {
                var location = await Geolocation.GetLocationAsync();
                if (location == null)
                    location = await Geolocation.GetLastKnownLocationAsync();

                if (location != null)
                {
                    this._data.Latitude = location.Latitude;
                    this._data.Longitude = location.Longitude;

                    var placemark = (await Geocoding.GetPlacemarksAsync(
                        location.Latitude, location.Longitude))?.FirstOrDefault();
                    if (placemark != null)
                    {
                        this._data.Locality = placemark.Locality;
                        this._data.ZipCode = placemark.PostalCode;
                        this._data.AdminArea = placemark.AdminArea;
                        this._data.Country = placemark.CountryName;
                    }
                }
                this._data.CreationDate = DateTime.Now;
                SaveDataToDb(this._data);
            }
            catch (Exception ex)
            {
                this._logger.WriteLogEntry(Logging.LoggingType.ERROR,
                    ex.Message + " GetLocationData() in class PositionServiceDroid");
            }
        }
    }
}

【问题讨论】:

  • 什么不起作用? broadcastReciver 和重复间隔使设备能够运行计划任务,而不管是否运行。
  • 究竟是什么问题?检查sample 看看是否有帮助。
  • 确切的问题是,如果我已经从我的应用程序启动了前台服务,并且如果我将应用程序置于后台或关闭 id,那么警报会被触发,并且即使启动,BroadcastReciver 中的代码也会被执行即使没有达到方法的触发参数

标签: android xamarin xamarin.forms xamarin.android


【解决方案1】:

您可以使用 Shiny ,它是 xamarin 后台和前台服务领域真正的问题解决者。 shiny getting started

【讨论】:

  • 我去看看那个
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-23
  • 2017-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-21
  • 2015-01-09
相关资源
最近更新 更多