Reputation: 1963
Xamarin released support for async
/await
which really simplifies the development of responsive UI in mobile platforms. I'd like to take advantage of it and increase the programming level of my code by using async/await stuff from now on.
However, since I'm relatively new to C# and haven't used async
/await
before I'm having trouble to find 'hooks' in my code that I can invoke async
methods. I know that event handlers are the typical places (where IoC happens), but imagine the following scenario:
I want to start background task when a ViewController is loaded (as opposed to when a button is pressed).
async Task PerformMyTaskAsync ()
{
// ...
await ... // another async API
// ...
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// .. initialize UI
await PerformMyTaskAsync ();
}
Obviously I can't await for PerformMyTaskAsync
in ViewDidLoad
because ViewDidLoad
is neither an async method nor an event handler.
What is the 'alternative' approach to start a background task when a view controller loads (or appears, whatever) ?
Upvotes: 9
Views: 4710
Reputation: 37967
So, running something async off the UI thread, from an event, looks like this:
Blah.OnEvent += onEvent;
protected async void onEvent(object sender, EventArgs ev)
{
...
}
The void
is not a typo - it's the antipattern that Xamarin follows for async UI events, unfortunately.
There are valid scenarios where you would want to run an async method that makes the UI wait. For example, calling Navigation.PushAsync()
off of a button click. But, you specifically asked for a background task, which implies it could take a while. For that, you don't want to make the UI wait; you should start the task and return immediately. For that you just use the same background task code you'd use in any C# TPL app:
public static void RunBg(Func<Task> fn)
{
Task.Run(fn).ConfigureAwait(false);
// Uncomment to roll up exceptions
//.GetAwaiter().GetResult();
}
public static void RunBgLong(Func<Task> fn)
{
Task.Factory.StartNew(fn, TaskCreationOptions.LongRunning).ConfigureAwait(false);
// Uncomment to roll up exceptions
//.GetAwaiter().GetResult();
}
I provide both because the creators of the TPL have gone out of their way to provide both underneath the hood. The meaning of the 2 is better explored in other questions, though I believe the distinction for "long" is a small number of milliseconds.
So, you'd start your task like:
public override void ViewDidLoad()
{
base.ViewDidLoad();
TaskHelper.RunBg(async () => {
await someBgAsyncMethodGoesHere(arg1, arg2);
);
}
Upvotes: 0
Reputation: 3504
The newest Xamarin Stable Channel releases support Async/Await overloads for ViewController Lifecycle methods. Try:
public async override void ViewDidLoad()
Upvotes: 19
Reputation: 89117
Not sure if this is the "best" approach, but have you tried firing an event from within ViewDidLoad(), and then in the handler for that event launching your Async code?
Upvotes: 0