Add IActivityApplicationLifetime for android (#18893)

* add lifetime with view factory on android

* rename android lifetime interface

* add warning when using ISingleViewApplicationLifetime for android, set current main activity reference on OnResume

* fix nit
This commit is contained in:
Emmanuel Hansen
2025-06-25 08:38:20 +00:00
committed by GitHub
parent 411b82f221
commit 56d94d64b9
8 changed files with 78 additions and 52 deletions
+8
View File
@@ -44,6 +44,10 @@ namespace ControlCatalog
{
desktopLifetime.MainWindow = new MainWindow { DataContext = new MainWindowViewModel() };
}
else if(ApplicationLifetime is IActivityApplicationLifetime singleViewFactoryApplicationLifetime)
{
singleViewFactoryApplicationLifetime.MainViewFactory = () => new MainView { DataContext = new MainWindowViewModel() };
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime)
{
singleViewLifetime.MainView = new MainView { DataContext = new MainWindowViewModel() };
@@ -97,6 +101,10 @@ namespace ControlCatalog
newWindow.Show();
oldWindow?.Close();
}
else if (app.ApplicationLifetime is IActivityApplicationLifetime singleViewFactoryApplicationLifetime)
{
singleViewFactoryApplicationLifetime.MainViewFactory = () => new MainView { DataContext = new MainWindowViewModel() };
}
else if (app.ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime)
{
singleViewLifetime.MainView = new MainView();
+4
View File
@@ -19,6 +19,10 @@ namespace SafeAreaDemo
{
desktop.MainWindow = new MainWindow();
}
else if (ApplicationLifetime is IActivityApplicationLifetime singleViewFactoryApplicationLifetime)
{
singleViewFactoryApplicationLifetime.MainViewFactory = () => new MainView();
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
{
singleViewPlatform.MainView = new MainView();
@@ -21,6 +21,10 @@ public class App : Application
{
desktopLifetime.MainWindow = new MainWindow();
}
else if (ApplicationLifetime is IActivityApplicationLifetime singleViewFactoryApplicationLifetime)
{
singleViewFactoryApplicationLifetime.MainViewFactory = () => new MainView();
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime)
{
singleViewLifetime.MainView = new MainView();
@@ -0,0 +1,28 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Logging;
namespace Avalonia.Android;
internal class ApplicationLifetime : IActivityApplicationLifetime, ISingleViewApplicationLifetime
{
private Control? _mainView;
public Func<Control>? MainViewFactory { get; set; }
public Control? MainView
{
get => _mainView; set
{
_mainView = value;
Logger.TryGet(LogEventLevel.Warning, LogArea.AndroidPlatform)?.Log(this, "ISingleViewApplicationLifetime.MainView is not fully supported on Android." +
" Consider setting IActivityApplicationLifetime.MainViewFactory.");
if (_mainView != null)
MainViewFactory = () => _mainView;
else
MainViewFactory = null;
}
}
}
@@ -9,13 +9,13 @@ namespace Avalonia.Android
{
internal interface IAndroidApplication
{
SingleViewLifetime? Lifetime { get; set; }
ApplicationLifetime? Lifetime { get; set; }
}
public class AvaloniaAndroidApplication<TApp> : global::Android.App.Application, IAndroidApplication
where TApp : Application, new()
{
SingleViewLifetime? IAndroidApplication.Lifetime { get; set; }
ApplicationLifetime? IAndroidApplication.Lifetime { get; set; }
protected AvaloniaAndroidApplication(nint javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
@@ -32,7 +32,7 @@ namespace Avalonia.Android
var builder = CreateAppBuilder();
builder = CustomizeAppBuilder(builder);
var lifetime = new SingleViewLifetime();
var lifetime = new ApplicationLifetime();
((IAndroidApplication)this).Lifetime = lifetime;
@@ -12,14 +12,20 @@ public class AvaloniaMainActivity : AvaloniaActivity
{
if (Application is IAndroidApplication application && application.Lifetime is { } lifetime)
{
initialContent ??= lifetime.MainView;
initialContent ??= lifetime.MainViewFactory?.Invoke();
_view = new AvaloniaView(this) { Content = initialContent };
lifetime.Activity = this;
_view = new AvaloniaView(this);
Content = initialContent;
}
if (_view is null)
throw new InvalidOperationException("Unknown error: AvaloniaView initialization has failed.");
}
protected override void OnResume()
{
base.OnResume();
if (Avalonia.Application.Current?.TryGetFeature<IActivatableLifetime>()
is AndroidActivatableLifetime activatableLifetime)
@@ -28,6 +34,17 @@ public class AvaloniaMainActivity : AvaloniaActivity
}
}
protected override void OnDestroy()
{
base.OnDestroy();
if (Avalonia.Application.Current?.TryGetFeature<IActivatableLifetime>()
is AndroidActivatableLifetime activatableLifetime && activatableLifetime.CurrentMainActivity == this)
{
activatableLifetime.CurrentMainActivity = null;
}
}
protected virtual AppBuilder CreateAppBuilder() => AppBuilder.Configure<Application>().UseAndroid();
protected virtual AppBuilder CustomizeAppBuilder(AppBuilder builder) => builder;
}
@@ -1,46 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
namespace Avalonia.Android;
internal class SingleViewLifetime : ISingleViewApplicationLifetime, ISingleTopLevelApplicationLifetime
{
private Control? _mainView;
private AvaloniaMainActivity? _activity;
/// <summary>
/// Since Main Activity can be swapped, we should adjust lifetime as well.
/// </summary>
public AvaloniaMainActivity Activity
{
[return: MaybeNull] get => _activity!;
internal set
{
if (_activity != null)
{
_activity.Content = null;
}
_activity = value;
_activity.Content = _mainView;
}
}
public Control? MainView
{
get => _mainView;
set
{
if (_mainView != value)
{
_mainView = value;
if (_activity != null)
{
_activity.Content = _mainView;
}
}
}
}
public TopLevel? TopLevel => _activity?._view?.TopLevel;
}
@@ -0,0 +1,11 @@
using System;
using Avalonia.Metadata;
namespace Avalonia.Controls.ApplicationLifetimes
{
[NotClientImplementable]
public interface IActivityApplicationLifetime : IApplicationLifetime
{
Func<Control>? MainViewFactory { get; set; }
}
}