Xamarin(Android)。手机锁定一段时间后,后台服务停止

时间:2017-09-11 11:41:24

标签: android xamarin service background xamarin.forms

我们在使用后台服务时遇到一些麻烦。即使应用程序关闭且手机被锁定,计时器也应该每秒执行一次代码。只要应用程序处于打开状态或后台并且手机正在使用中,此功能就可以正常工作,但是当手机处于锁定状态并处于待机状态时,服务会在一段时间后自动停止。

代码以此示例为模型: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秒后更早地暂停计时器。

如何更改代码,以便在手机锁定和睡眠时后台服务在所有设备上成功运行?

提前致谢!

2 个答案:

答案 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;将现有服务推广到前台服务)解决了这个问题。