Browse Source

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
pull/19123/head
Emmanuel Hansen 1 year ago
committed by GitHub
parent
commit
56d94d64b9
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 8
      samples/ControlCatalog/App.xaml.cs
  2. 4
      samples/SafeAreaDemo/App.xaml.cs
  3. 4
      samples/SingleProjectSandbox/App.axaml.cs
  4. 28
      src/Android/Avalonia.Android/ApplicationLifetime.cs
  5. 6
      src/Android/Avalonia.Android/AvaloniaAndroidApplication.cs
  6. 23
      src/Android/Avalonia.Android/AvaloniaMainActivity.cs
  7. 46
      src/Android/Avalonia.Android/SingleViewLifetime.cs
  8. 11
      src/Avalonia.Controls/ApplicationLifetimes/IActivityApplicationLifetime.cs

8
samples/ControlCatalog/App.xaml.cs

@ -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
samples/SafeAreaDemo/App.xaml.cs

@ -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();

4
samples/SingleProjectSandbox/App.axaml.cs

@ -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();

28
src/Android/Avalonia.Android/ApplicationLifetime.cs

@ -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;
}
}
}

6
src/Android/Avalonia.Android/AvaloniaAndroidApplication.cs

@ -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;

23
src/Android/Avalonia.Android/AvaloniaMainActivity.cs

@ -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;
}

46
src/Android/Avalonia.Android/SingleViewLifetime.cs

@ -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;
}

11
src/Avalonia.Controls/ApplicationLifetimes/IActivityApplicationLifetime.cs

@ -0,0 +1,11 @@
using System;
using Avalonia.Metadata;
namespace Avalonia.Controls.ApplicationLifetimes
{
[NotClientImplementable]
public interface IActivityApplicationLifetime : IApplicationLifetime
{
Func<Control>? MainViewFactory { get; set; }
}
}
Loading…
Cancel
Save