用作异步任务时后台服务错误 [英] Background Service error while using as async Task

查看:61
本文介绍了用作异步任务时后台服务错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Xamarin Android中有一个后台服务,但问题是我不能将其用作 Async 方法,它给出了一个错误.

I have a background service in Xamarin Android but the problem is I cannot use it as Async method, it gives an error.

返回类型必须为'StartCommandResult',以匹配被覆盖的成员'Service.OnStartCommand(Intent,StartCommandFlags,int)

return type must be 'StartCommandResult' to match overridden member 'Service.OnStartCommand(Intent, StartCommandFlags, int)

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

The actual overridden method is void but to use await I have to change it to async Task<T> and then it produces the error. I searched everywhere but couldn't find a proper solution on this.

整个类的代码段在这里:

The code snippet for entire class is here:

{
 [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 .但是,如果我错了,那我有什么方法想念的吗?也许还有另一种方法可以做到这一点,但我不知道.

As far as I know it should work because I am returning StartCommandResult in override method. But if I am wrong then is there any method that I am missing? Maybe there is another way to do this and I don't know that.

更新和解决方案

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

I ended up implementing another new IntentService class to do all the background updating work while the above service only handles the calling of the IntentService. The service is called with an explicit intent as any other service.

 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.");
    }
 }

推荐答案

这是因为方法 OnStartCommand rel ="nofollow noreferrer"> Service 的返回类型为 StartCommandResult ,而不是 Task< StartCommandResult> ,因此您无法更改返回类型在子类中重写时的方法的说明.

This is because the method OnStartCommand defined in the base class Service has return type StartCommandResult not Task<StartCommandResult>, so you cannot change the return type of a method when overriding in the child class.

如果要使其异步,您可以创建一个代理方法,例如:

You can create a proxy method if you want to make it async like:

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

和异步方法将是:

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 方法返回结果为止,因此基本上异步方法

But note that it wouldn't serve you the purpose you want, because .Result will block the thread until the async method returns the result, so it is basically the async method synchronously

以供参考请参阅此帖子.

这篇关于用作异步任务时后台服务错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆