Whenever you await
a Task
you're effectively creating a callback out of everything that occurs after that await
statement and attaching it to the Task
as a continuation.
You don't necessarily need a continuation, although if you want to confirm from your calling code that the asynchronous execution completed successfully/with an error, or you want to use the result of the asynchronous action, you need to either await
the response or attach a continuation (.ContinueWith()
.)
In your first example this line:
var expands = await APICalls.GetExpandsAsync();
Is inside the continuation callback of the first, meaning it won't be dispatched until the first asynchronous call returns. The second snippet dispatches two asynchronous actions, but only awaits the first, so by the point that the continuation occurs the second task might not have completed.
To await both both you need to use Task.WhenAll
:
var configs = APICalls.GetConfigurationsAsync();
var expands = APICalls.GetExpandsAsync();
await Task.WhenAll(configs, expands);
// Access the values through "configs.Result" and "expands.Result"
As for the second issue the reason the UI thread freezes is because the asynchronous action is being awaited inside a method that's called on the UI thread. The way around that is to await your async calls inside a Task.Run
call which will cause the execution to occur on a new thread. Once your async action is done if you want to interact with UI elements you just need to make sure this is done on the UI thread, so you'll need to wrap any UI logic in a Device.BeginInvokeOnMainThread
call. A better example is here: