0

Code examples will use Xamarin Android.

I am extending the IntentService. It has few lifecycle methods. In particular, void OnHandleIntent(Intent intent) where you do actual work, and void OnDestroy() which is called by the system when it sees that the service finished working and it's time to destroy it. For IntentService, the end of its life is when OnHandleIntent returns.

Being an event-like method, it's OK to use async void OnHandleIntent. Consider following code

protected override async void OnHandleIntent(Intent intent)
{
    Debug.Out("OnHandleIntent Start");
    await Task.Run(async () => await Task.Delay(1000));
    Debug.Out("OnHandleIntent End");
}

protected override void OnDestroy(Intent intent)
{
    base.OnDestroy();
    Debug.Out("OnDestroy");
}

The output is:

Debug.Out("OnHandleIntent Start");
Debug.Out("OnDestroy");
Debug.Out("OnHandleIntent End");

At the same time, following (blocking) code works as expected

protected override void OnHandleIntent(Intent intent)
{
    Debug.Out("OnHandleIntent Start");
    Task.Run(async () => await Task.Delay(1000)).Wait();
    Debug.Out("OnHandleIntent End");
}

protected override void OnDestroy(Intent intent)
{
    base.OnDestroy();
    Debug.Out("OnDestroy");
}

The output is:

Debug.Out("OnHandleIntent Start");
Debug.Out("OnHandleIntent End");
Debug.Out("OnDestroy");

The question is - why does it happens?

Ingweland
  • 1,073
  • 1
  • 13
  • 25
  • Because the 2nd one is blocking. I don't understand the question, you seem to understand that the 2st one is blocking and the first is not. – Andrei Tătar Oct 10 '19 at 11:27
  • 1
    The first one is blocking the execution of the OnHandleIntent method, in the sense that the code after the await will only execute once the task you're awaiting has completed. However, the code that called your OnHandleIntent will continue executing, because once your OnHandleIntent method reaches await, and that task isn't already completed, the method will return. So the calling code moves on and calls Destroy, before your task has completed. – Lasse V. Karlsen Oct 10 '19 at 11:28
  • 1
    BTW The use of Task.Run here is only for wasting resources and adding noise to the code. Task.Delay() already returns a task you can await or wait for – Sir Rufo Oct 10 '19 at 11:30
  • Possible duplicate of [async/await - when to return a Task vs void?](https://stackoverflow.com/questions/12144077/async-await-when-to-return-a-task-vs-void) – FreakyAli Oct 10 '19 at 11:38
  • @FreakyAli No, that question is different – Ingweland Oct 10 '19 at 12:10

1 Answers1

1

async void methods cannot be awaited by the caller (because no Task is returned to wait for).

The first implementation will return before Delay is done; it will be executed as a fire and forget operation.


Btw.

await Task.Run(async () => await Task.Delay(1000))

can be

await Task.Delay(1000))
tymtam
  • 31,798
  • 8
  • 86
  • 126