Home > Mobile >  Table creation is stalling without throwing exception
Table creation is stalling without throwing exception

Time:11-03

My PlayerService class:

public static class PlayerService
    { 
        private static SQLiteAsyncConnection db;

        /// <summary>
        /// Creates database
        /// if Its created already it will use that instance
        /// </summary>
        /// <returns></returns>
        static async Task Init()
        {
            if(db != null) 
                return;

            db = new SQLiteAsyncConnection(DatabaseConstants.DatabasePath);
            await db.CreateTableAsync<Player>();
        }

        /// <summary>
        /// Adds player to the database
        /// </summary>
        /// <param name="playerName"></param>
        /// <param name="playerAlias"></param>
        /// <param name="playerTeam"></param>
        /// <returns>id</returns>
        public static async Task AddPlayerAsync(string playerName, string playerAlias, string playerTeam = null)
        {
            await Init();
            var player = new Player
            {
                Name = playerName, Alias = playerAlias, Team = playerTeam
            };
            await db.InsertAsync(player);
        }

Database is created in Init(), but halts on asynchronous db.CreateTableAsync<Player>() without throwing an exception.

View Model:

public partial class ManagePlayersPageViewModel : ObservableObject
    {
        /// <summary>
        /// List of players being displayed 
        /// </summary>
        [ObservableProperty] private ObservableCollection<Player> players;

        public ManagePlayersPageViewModel()
        {
            Players = PlayerService.GetAllPlayersAsync().Result.ToObservableCollection();
        }

I already cleaned and rebuild, updated dependencies and have raw.bundle.green.

CodePudding user response:

Your code is "deadlocked". This Xamarin.Forms Q&A explains the concept. SQLite-NET-PCL Stuck on CreateTableAsync().

Bottom line: DO NOT use .Result with an async method. Especially in a constructor. Instead, get into an async context, by wrapping that code.

For Maui:

MainThread.BeginInvokeOnMainThread( async () =>
  {  // On MainThread.
    var players1 = await PlayerService.GetAllPlayersAsync();
    Players = players1.ToObservableCollection();
  });

OR, if GetAllPlayersAsync takes a long time, might be safer to call it from a background thread:

Task.Run( async () =>
  {  // On background thread.
    var players1 = await PlayerService.GetAllPlayersAsync();
    // Because Players affects UI, safest to get back on MainThread:
    MainThread.BeginInvokeOnMainThread( async () =>
      {  // On MainThread.
        Players = players1.ToObservableCollection();
      });
  });
  • Related