I have been following this tutorial to implement SQLite-net into my MAUI application. Whenever the program executes "await db.CreateTableAsync<Restroom>();", the whole application freezes up. I have tried several solutions, including trying to prevent deadlock with ConfigureAwait(false) as shown in this blog, and using MainThread.BeginInvokeOnMainThread as shown in this thread and this thread. Both of these threads didn't work because the solutions still called CreateTableAsync since it's inside of the InitAsync Task.
I have also tried:
-Updating all my dependencies.
-Implementing raw.bundle.green.
-Creating a whole new project to see if the issue will be replicated (it was).
-Removing the Location property of Restroom model and adjusting the code accordingly.
-Adding <EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk> to .csproj, to turn off Fast Deploy as per this answer.
What could be the issue?
Restroom.cs
using SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dook.Model
{
public class Restroom
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Username { get; set; }
public Location PinLocation { get; set; }
}
}
RestroomService.cs
using Dook.Model;
using SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dook.Services
{
public static class RestroomService
{
static SQLiteAsyncConnection db;
static async Task InitAsync()
{
if(db != null)
return;
//Get an absolute path to the database file
var databasePath = Path.Combine(FileSystem.AppDataDirectory, "MyData.db");
db = new SQLiteAsyncConnection(databasePath);
await db.CreateTableAsync<Restroom>();
}
public static async Task AddPinAsync(string name, string address, string username, Location location)
{
await InitAsync();
var test = "test";
var restroom = new Restroom
{
Name = name,
Address = address,
Username = username,
PinLocation = location
};
var id = await db.InsertAsync(restroom);
}
public static async Task RemovePinAsync(int id)
{
await InitAsync();
await db.DeleteAsync<Restroom>(id);
}
public static async Task<IEnumerable<Restroom>> GetPinAsync()
{
await InitAsync();
var restroom = await db.Table<Restroom>().ToListAsync();
return restroom;
}
}
}
MainViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
using Dook.Model;
using Dook.Services;
using MvvmHelpers;
using MvvmHelpers.Commands;
using CommunityToolkit.Maui.Core.Extensions;
namespace Dook.ViewModel
{
public partial class MainViewModel : BaseViewModel
{
public ObservableRangeCollection<Restroom> Restroom { get; set; }
public AsyncCommand RefreshCommand { get; }
public AsyncCommand<Location> AddCommand { get; }
public AsyncCommand<Restroom> RemoveCommand { get; }
public MainViewModel()
{
Title = "Map Controller";
//var restroom1 = RestroomService.GetPin().Result;
//Restroom = restroom1 as ObservableRangeCollection<Restroom>;
Restroom = new ObservableRangeCollection<Restroom>();
AddCommand = new AsyncCommand<Location>(Add);
RemoveCommand = new AsyncCommand<Restroom>(Remove);
RefreshCommand = new AsyncCommand(Refresh);
}
async Task Add(Location pinlocation)
{
var name = await App.Current.MainPage.DisplayPromptAsync("Location Name", "Name of Location");
// var address = "Latitude: {pinlocation.Latitude}, Longitude: {pinlocation.Longitude}, Altitude: {location.Altitude}";
var address = "test";
var username = await App.Current.MainPage.DisplayPromptAsync("Username", "Username of Toilet Adder");
Location location = pinlocation;
if(name == null || address == null || username == null) { return; }
await RestroomService.AddPinAsync(name, address, username, location);
await Refresh();
}
async Task Remove(Restroom restroom)
{
await RestroomService.RemovePin(restroom.Id);
await Refresh();
}
async Task Refresh()
{
IsBusy = true;
await Task.Delay(2000);
Restroom.Clear();
var restrooms = await RestroomService.GetPin();
Restroom.AddRange(restrooms);
IsBusy = false;
}
public static Location GetLocation()
{
try
{
Location location = new();
location = Geolocation.Default.GetLastKnownLocationAsync().Result;
if (location != null)
return location;
}
catch (Exception ex)
{
Debug.WriteLine($"Unable to get location: {ex.Message}");
Application.Current.MainPage.DisplayAlert("Error!", ex.Message, "OK");
}
return null;
}
}
}
MainPage.xaml.cs
namespace Dook;
using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using System.Diagnostics;
using Map = Microsoft.Maui.Controls.Maps.Map;
using Dook.ViewModel;
using Dook.Model;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
MoveMapLocation();
}
private void GoToLocation_Button(object sender, EventArgs e)
{
MoveMapLocation();
}
private void OnMapClicked(object sender, MapClickedEventArgs e)
{
var viewModel = new MainViewModel();
if(viewModel.AddCommand.CanExecute(e.Location))
viewModel.AddCommand.ExecuteAsync(e.Location);
}
private void RefreshButton_Clicked(object sender, EventArgs e)
{
RefreshPins();
}
private void MoveMapLocation()
{
//Function to avoid boilerplate code
MapSpan mapSpan = new MapSpan(MainViewModel.GetLocation(), 0.01, 0.01);
mainmap.MoveToRegion(mapSpan);
}
private void RefreshPins()
{
var viewModel = new MainViewModel();
viewModel.RefreshCommand.ExecuteAsync();
}
}
