Reputation: 149
In maui android app, when app was moved to back it occassionally invokes Destroy and bringing app back to front, throws an exeption:
Either set MainPage or override CreateWindows.
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState); <- throws here
}
i tried to override code in App class:
protected override Window CreateWindow(IActivationState activationState)
{
return base.CreateWindow(activationState); <- throws here
}
System.NotImplementedException: 'Either set MainPage or override CreateWindow.'
also tried to restore previously successfully loaded window:
private Window _window = null;
protected override Window CreateWindow(IActivationState activationState)
{
if (MainPage == null && _window != null)
{
return _window;
}
return _window = base.CreateWindow(activationState);
}
but app stays unresponsive after it. Tried to use in AndroidManifest.xml options:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:networkSecurityConfig="@xml/network_security_config" android:alwaysRetainTaskState="true" android:killAfterRestore="false" android:noHistory="false" android:excludeFromRecents="false" android:persistent="true" android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
none of that had a way to prevent from destroying app.
Part of my StartupClass:
public static MauiApp CreateMauiApp()
{
MauiAppBuilder builder = MauiApp.CreateBuilder();
builder.UsePrismApp<App>(prism =>
{
prism.RegisterTypes(containerRegistry =>
{
//list of pages
containerRegistry.RegisterForNavigation<NavigationPage>();
....
})
.OnAppStart(async (containerProvider, navigationService) =>
{
var navService = containerProvider.Resolve<INavigationService>();
await navService.NavigateAsync(nameof(MyPage));
});
here i use prism over maui. So is there any way to prevent app from destroying or to successfully restore app state on recreate?
Upvotes: 7
Views: 7226
Reputation: 73
Well, as seen everywhere on the internet this issue is particularly unclear. I found a solution to this problem I had, migrating from MAUI 8 packages to MAUI 9.0.1. Have a look at the code samples from github :
namespace DeveloperBalance;
public partial class App : Application
{
public App()
{
InitializeComponent();
}
protected override Window CreateWindow(IActivationState? activationState)
{
return new Window(new AppShell());
}
}
This snippet of code was sourced from here (github maui-samples/9.0/9.0/Apps/DeveloperBalance/App.xaml.cs).
Heck, the code itself is trivial, but the doc is still quite terrible, coming from a deprecation warning we could have hopped for a more guided approach.
Hope this helps, it did the trick on my project at least.
Upvotes: 1
Reputation: 41
In my opinion this message is misleading in MAUI 9. If you check the underlying MAUI code, it seems there's a nicer decoupled mechanism relying on a DI-injected IWindowCreator
. There an open question about the exact intended use on the MAUI Github.
The current mechanism in MAUI is somewhat ambiguous, it leaves three different approaches.
Create the page and the window in an override of Application.CreateWindow
. Call base.CreateWindow
first and use the window returned by that, if any. Most likely this'll never return any window, but otherwise you'll skip some guards and window deduplication code that might be pertinent in some situations.
I do not recommend this, but it can be achieved by adding this to your Application
class:
protected override Window CreateWindow(IActivationState? activationState)
{
ArgumentNullException.ThrowIfNull(activationState);
var window = base.CreateWindow(activationState) ?? new();
// Set your main page.
window.Page = activationState?.Context.Services.GetRequiredService<AppShell>();
return window;
}
As the name IWindowCreator
suggests, create the window in the IWindowCreator
using an base.CreateWindow
call in an override of Application.CreateWindow
that then sets the Page
of the window returned from the base
call.
While this method is the most logical based on the MAUI code base, it doesn't seem to be the intended method, so I'll not give an example.
Documentation of IWindowCreator
suggests that it should not only create the window, but also set its page to the main page. The documentation seems to disregard that it might be called to create subsequent non-main windows. My proposed solution below improves on the documentation in these ways:
IWindowCreator
is used to create subsequent (and hence non-main) windows.Register this implementation of IWindowCreator
in DI with: .AddSingleton<IWindowCreator, WindowCreator>()
. After doing so, you don't need to override CreateWindow
or set MainPage
in you Application
class.
public class WindowCreator : IWindowCreator
{
public Window CreateWindow(Application app, IActivationState? activationState)
{
var window = new Window();
if (!app.Windows.Any())
{
// First window created shows the main page.
// Note: Your main page class will most likely be different.
window.Page = activationState?.Context.Services.GetRequiredService<AppShell>();
}
return window;
}
}
Upvotes: 0
Reputation: 1
The solution is to ensure that MainPage
is set on the main thread using MainThread.BeginInvokeOnMainThread
, as recommended by .NET MAUI for any UI-related operations.
public App()
{
try
{
InitializeComponent();
// Use MainThread to ensure MainPage is set on the main thread
MainThread.BeginInvokeOnMainThread(() =>
{
this.MainPage = new AppShell();
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Upvotes: 0
Reputation: 16562
If this crash occurs on startup then it probably has to do with your Styles.xaml or Colors.xaml
One of these files is trying to either refer to something that does not exist or you have tried to use a StaticResource that was not created yet or does not exist.
A good way to make sure this is what is causing the issue is to put a try-catch block on your App class's InitializeComponent method and see if one of these files is throwing the exception or not.
In my case I faced this issue because i deleted all the colors and yet these colors were being referred in the styles file
Upvotes: 1
Reputation: 19
I encountered the same problem myself lately. I'm using Shiny.Framework. But even the sample provided by Shiny.Framework throws the exception.
I googled some more, this comment from maui repo shows me maybe this is an emulator problem. So I created a new emulator using the latest Android 33 image, and the problem went away.
I currently find that the default iamge comes with VS 2022, which is Android 29, will always throw the exception. I tried, it seems that images above android v31 works fine.
And PS:
The exception I have also had this message:
(Sample) ChildIndex <= -1, Parent: App Child: PrismWindow
So I think it has something to do with Prism. But I'm no expert on Prism or Shiny, so I can't dig any deeper. Hoper some one can solve this mystery.
Upvotes: 1
Reputation: 4332
Maui android. Either set MainPage or override CreateWindows
About override CreateWindows, you can try to use following code:
protected override Window CreateWindow(IActivationState activationState)
{
if (this.MainPage == null)
{
this.MainPage = new MainPage();
}
return base.CreateWindow(activationState);
}
For more info you can refer to this issue: [Android] App crashes when start from background. Wish it can help you.
Upvotes: 3