Reputation: 750
I have a background service in Xamarin Android but the problem is I cannot use it as Async
method, it gives an error.
return type must be 'StartCommandResult' to match overridden member 'Service.OnStartCommand(Intent, StartCommandFlags, int)
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}).");
}
}
}
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.
Update and Solution
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.");
}
}
Upvotes: 2
Views: 1191
Reputation: 62498
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;
}
and the async method would be like:
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;
}
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
For reference see this post.
Upvotes: 2