我们在使用后台服务时遇到一些麻烦。即使应用程序关闭且手机被锁定,计时器也应该每秒执行一次代码。只要应用程序处于打开状态或后台并且手机正在使用中,此功能就可以正常工作,但是当手机处于锁定状态并处于待机状态时,服务会在一段时间后自动停止。
代码以此示例为模型:http://arteksoftware.com/backgrounding-with-xamarin-forms/
此代码在MainActivity中执行:
MessagingCenter.Subscribe<StartBackgroundTimer>(this, "StartBackgroundTimer", message =>
{
var intent = new Intent(this, typeof(LongRunningTaskService));
StartService(intent);
});
MessagingCenter.Subscribe<StopBackgroundTimer>(this, "StopBackgroundTimer", message =>
{
var intent = new Intent(this, typeof(LongRunningTaskService));
StopService(intent);
});
这是LongRunningTaskService类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using System.Threading;
using System.Threading.Tasks;
using OurAppNamespace.Classes;
using Xamarin.Forms;
namespace OurAppNamespace.Droid
{
[Service]
public class LongRunningTaskService : Service
{
CancellationTokenSource _cts;
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
_cts = new CancellationTokenSource();
Task.Run(() =>
{
try
{
//INVOKE THE SHARED CODE
var timer = new BackgroundTimer();
timer.RunBackgroundTimer(_cts.Token).Wait();
}
catch (System.OperationCanceledException)
{
}
finally
{
if (_cts.IsCancellationRequested)
{
var message = new BackgroundTimerCancelledMessage();
Device.BeginInvokeOnMainThread(
() => MessagingCenter.Send(message, "BackgroundTimerCancelledMessage")
);
}
StopSelf();
}
}, _cts.Token);
return StartCommandResult.Sticky;
}
public override void OnCreate()
{
base.OnCreate();
}
public override void OnDestroy()
{
if (_cts != null)
{
_cts.Token.ThrowIfCancellationRequested();
_cts.Cancel();
}
base.OnDestroy();
}
}
}
然后,在PCL中:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace OurAppNamespace.Classes
{
public class StartBackgroundTimer { }
public class StopBackgroundTimer { }
public class BackgroundTimerMessage
{
}
public class BackgroundTimerCancelledMessage { }
public class BackgroundTimer
{
public async Task RunBackgroundTimer(CancellationToken token)
{
await Task.Run(async () =>
{
while (true)
{
token.ThrowIfCancellationRequested();
await Task.Delay(1000);
Device.BeginInvokeOnMainThread(() =>
{
MessagingCenter.Send<BackgroundTimerMessage>(new BackgroundTimerMessage(), "BackgroundTimer");
});
}
}, token);
}
}
}
最后,在BackgroundTimer调用后执行的代码:
private static void UpdateActiveTimers()
{
MessagingCenter.Subscribe<BackgroundTimerMessage>(instance, "BackgroundTimer", message =>
{
(unrelated code)
DependencyService.Get<INotificationHandling>().UpdateTimerNotification(timeText);
}
});
}
启动计时器10分钟时,不同的手机会有不同的结果。
小米Redmi Note 3 Pro可以在后台使用该应用程序执行此代码,并将手机锁定10分钟(不再测试)。
Blackberry Priv工作正常,大约2分钟,应用程序在后台和手机锁定(然后进入待机状态),然后计时器冻结/通知不再更新,直到手机再次打开(解锁)不需要)。
通知显示计时器的剩余时间。当手机被锁定时,计时器似乎暂停并在手机再次解锁时恢复。当手机在计时器上停留20分钟并且在10分钟后解锁时,计时器将在大约18分钟后重新开始计时。
HOMTOM HT16显示与Blackberry Priv相同的行为,但它在约30秒后更早地暂停计时器。
如何更改代码,以便在手机锁定和睡眠时后台服务在所有设备上成功运行?
提前致谢!
答案 0 :(得分:1)
您的问题可能与新的&#34; Doze&#34; Android中的模式(API 23+)。它搞砸了所有背景任务。请看这个链接: https://developer.android.com/training/monitoring-device-state/doze-standby.html
答案 1 :(得分:1)
我要感谢SushiHangover的评论,使用Foreground Service( - &gt;将现有服务推广到前台服务)解决了这个问题。