使用async任务时出现后台服务错误

时间:2017-01-19 06:36:04

标签: c# asynchronous service xamarin.android

我在Xamarin Android中有后台服务,但问题是我无法将其用作Async方法,它会出错。

  

返回类型必须是'StartCommandResult'才能匹配重写成员'Service.OnStartCommand(Intent,StartCommandFlags,int)

实际重写的方法是void但是要使用await我必须将其更改为async Task<T>,然后它会产生错误。我到处搜索,但找不到合适的解决方案。

整个班级的代码段在这里:

{
 [Service(IsolatedProcess = false, Enabled = true, Label = "BackgroundNotificationService")]
class BackgroundNotificationService : Service
{
    static readonly string TAG = "X:" + typeof(BackgroundNotificationService).Name;
    static readonly int TimerWait = 3600000;
    Timer timer;
    DateTime startTime;
    bool isStarted = false;

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

    public override void OnCreate()
    {
        base.OnCreate();
    }

    public override void OnDestroy()
    {
        timer.Dispose();
        timer = null;
        isStarted = false;

        TimeSpan runtime = DateTime.UtcNow.Subtract(startTime);
        Log.Info(TAG, $"Simple Service destroyed at {DateTime.UtcNow} after running for {runtime:c}.");
        base.OnDestroy();
    }

    public override async Task<StartCommandResult> OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        StartCommandResult a = StartCommandResult.NotSticky;
        Log.Debug(TAG, $"OnStartCommand called at {startTime}, flags={flags}, startid={startId}");
        if (isStarted)
        {
            TimeSpan runtime = DateTime.UtcNow.Subtract(startTime);
            Log.Info(TAG, $"This service was already started, it's been running for {runtime:c}.");
            await UpdateData();
        }
        else
        {
            startTime = DateTime.UtcNow;
            Log.Info(TAG, $"Starting the service, at {startTime}.");
            timer = new Timer(HandleTimerCallback, startTime, 0, TimerWait);
            isStarted = true;
            await UpdateData();
        }
        return a;
    }

    void HandleTimerCallback(object state)
    {
        TimeSpan runTime = DateTime.UtcNow.Subtract(startTime);
        Log.Info(TAG, $"This service has been running for {runTime:c} (since ${state}).");
    }


}
}

据我所知它应该有效,因为我在覆盖方法中返回StartCommandResult。但如果我错了,那么有什么方法可以让我失踪吗?也许有另一种方法可以做到这一点,我不知道。

更新和解决方案

我最终实现了另一个新的IntentService类来完成所有后台更新工作,而上述服务只处理IntentService的调用。与其他任何服务一样,该服务具有明确的意图。

 public class CustomIntentService : IntentService
{
    public CustomIntentService() : base("CustomIntentService")
    {
    }

    protected override async void OnHandleIntent(Intent intent)
    {
        // do your work
        string servicename = typeof(CustomIntentService).Name;
        Log.Info(servicename, "Starting background work");
        try
        {
            await UpdateData();
        }
        catch (Exception ex)
        {
            Log.Info(servicename, "Background work returned with errors.\nError:" + ex.Message);
            return;
        }
        Log.Info(servicename, "Background work completed without errors.");
    }
 }

1 个答案:

答案 0 :(得分:0)

这是因为基类OnStartCommand中定义的方法Service的返回类型为StartCommandResult而不是Task<StartCommandResult>,因此在覆盖时无法更改方法的retirn类型在儿童班。

如果要将其设置为异步,则可以创建代理方法,如:

public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
        return OnStartCommandAsync(intent,flags,startId).Result;
}

,async方法就像:

private async Task<StartCommandResult> OnStartCommandAsync(Intent intent, StartCommandFlags flags, int startId)
{
  StartCommandResult a = StartCommandResult.NotSticky;
        Log.Debug(TAG, $"OnStartCommand called at {startTime}, flags={flags}, startid={startId}");
        if (isStarted)
        {
            TimeSpan runtime = DateTime.UtcNow.Subtract(startTime);
            Log.Info(TAG, $"This service was already started, it's been running for {runtime:c}.");
            await UpdateData();
        }
        else
        {
            startTime = DateTime.UtcNow;
            Log.Info(TAG, $"Starting the service, at {startTime}.");
            timer = new Timer(HandleTimerCallback, startTime, 0, TimerWait);
            isStarted = true;
            await UpdateData();
        }
        return a;
}

但请注意,它不会为您提供所需的目的,因为.Result将阻塞该线程,直到async方法返回结果,因此它基本上是同步的异步方法< / p>

供参考see this post