Xamarin.Forms Async Task On Startup

When you start up your Xamarin.Forms application, the constructor in your App.xaml.cs will be run, before your application is shown on screen. As you are well aware, constructors currently don’t have the ability to await async methods. They are a number of ways to solve this, depending upon your exact situation.

Not Dependent Upon Result

If you do not care about the result of your async Task, and you just want to run it, then you can do it in the constructor, and even just push it to a background thread.

Task.Run(async ()=> { await MyMethod(); });

However, it would be recommended to actually place it in the OnStart method. Add the async keyword in here. Since OnStart is just an event, and nothing is waiting for it’s return, using async void is acceptable here.

protected override async void OnStart()
{
    // Handle when your app starts
}

Required Before App Start

If you need this to run, before your app starts, and it’s not required to run on the UI Thread, you have the option to Wait your async Task.

Task.Run(async()=>{ await MyMethod(); }).Wait();

You must be careful with this approach, as if this task, calls the UI Thread at any point, it will cause a deadlock.

The other option, is to launch a loading screen. If you have control over your app, then set the MainPage to a loading screen.

MainPage = new LoadingPage();

Then run your tasks in OnStart, and when they are finished, load your actual application.

protected override async void OnStart()
{
    await MyMethod();

    MainPage = new MyActualApplicationPage();
}

Required Before App Start On UI Thread

If none of these work for you because you have to do an async task, in the constructor, on the UI Thread, then there is an option for this. The code itself is a little complex to explain, hence you can just copy the Exrin ThreadHelper.cs and place it in your project.

Exrin.Common.ThreadHelper.Init(SynchronizationContext.Current);
Exrin.Common.ThreadHelper.RunOnUIThread(async () => { await MyMethod(); });

This will run the async method, on the same thread, and will not proceed until it is complete. While requiring an async method to run on the UI Thread in the constructor is a rare occurrence, it can be required sometimes, but this is considered one of the last options you should try.


XAMARIN.FORMS MONTHLY NEWSLETTER

JOIN 1,100+ SUBSCRIBERS

  1. Don't miss out on updates
  2. The latest info from this site, Xamarin and the community
  3. Unsubscribe at any time*

* We use MailChimp, with double opt-in, and instant unsubscribe

Microsoft MVP | Xamarin MVP | Xamarin Certified Developer | Exrin MVVM Framework | Xamarin Forms Developer | Melbourne, Australia

Related Posts

9 Comments

  1. Eric Brunner

    Thanks for sharing that solutions. In app development I first learned to add a solid exception handling , especially with aaynchronous programming. Therefore I would strongly suggest to wrap a try-catch (AggregateException) around the awaited task of the second Task.Run(….).Wait(); statement and inside the lamdas, too to introduce some fail safe mechanisms. Uncaught exceptions in .ctors are terrible because a further attempt to create an instance of that class would fail.

    In general I prefer the OnStart method as you described for “real” asynchronous code.

    The Application instance could be created by introducing a factory pattern and put an awaited InitializeAync in the CreateInstance method, too.

    1. Adam Pedley

      Thanks, a good tip to concern yourself with exceptions, especially in Tasks. Using the
      .ContinueWith((t)=> {
      if (t.Exception != null)
      // Do something
      });

      Is another way to detect an unhandled exception.

    1. Adam Pedley

      Hi Eric

      Since the UI hasn’t been loaded yet, using .Wait() is acceptable, but as mentioned, you need to be careful, with deadlocks. Meaning you can’t switch back to the UI Thread, in that background thread. I do try to avoid using .Wait() or .Result, and I certainly don’t use them once the app is loaded.

      The Factory Pattern and Composing with Asynchronous Initialization are ok, but it still doesn’t block construction. When we are starting Xamarin Forms, that App constructor needs to return to finish loading the app. If we MUST complete something in the constructor before the app loads, these patterns don’t cut it. We have no async capable function of sitting there and waiting for the result. It all has to be done synchronously.

      If you can return from the constructor, then continue on with the async operation, I would just recommend putting it in OnStart, and it saves all that additional setup anyway.

      Thanks for providing another alternative. 🙂

  2. Miha Svalina

    Thanks for Adam for this, you saved the day.

    I’m using the second approach for checking if SQLite database on mobile device already exists. It it doesn’t create tables. Additionally database migrations can be put on OnStart method. Maybe I’l switch to LoadingPage/MigrationPage.

    {code}
    protected override void OnStart()
    {
    Task.Run(async () =>
    {
    // !Don’t call UI thread (if this task, calls the UI Thread at any point, it will cause a deadlock.)
    IFileHelper fileHelper = DependencyService.Get();
    string dbPath = fileHelper.GetLocalFilePath(dbFilename);

    // if sqlite database file doesn’t exist yet, create tables afterwards
    if (!fileHelper.FileExists(dbPath))
    await Database.InitAsync();

    await DbMigration();
    }).Wait();
    }
    {code}

  3. Miha Svalina

    Actually next code doesn’t work on iOS:

    protected override async void OnStart()
    {
    // throws NSInternalInconsistencyException: Application windows are expected to
    // have a root view at the end of application
    await Task.Delay(5000);

    // throws the same exception
    //string a = await Common.Settings.GetSysSettingAsync(“User.Username”);
    //Task.Delay(5000).Wait(); // WORKS OK on Android and iOS
    this.MainPage = new LoginPage();
    }

    Perhaps I don’t understand how await works. But I’m sure that code after await executes when await finishes.

    1. Adam Pedley

      This error is saying you haven’t set the MainPage yet. You need to make sure your MainPage is set in the constructor first, before you do anything in OnStart. Even if its just setting it to a blank ContentPage in the meantime. Though would recommend some kind of splashscreen or loading message on that page, if you go that route.

  4. Miha Svalina

    Adding this.MainPage = new Page() solved the problem. Now I can use await without Task.Run in OnStart method. Perhaps DbMigration page can be used as a LoadingPage.