From ed8b2916ebf5fa07464af7660af80edf706acc34 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 13 Jun 2022 09:51:26 -0500 Subject: [PATCH 1/2] [essentials] use Lazy for Android application-wide values Context: https://github.com/unoplatform/performance/tree/master/src/dopes/DopeTestMaui I was reviewing a benchmark/sample that puts lots of labels on the screen that say "dope" and measures how many per second. Personally, I would have chosen some other word like `LOL`, so you could have a `LOLs/s` average. LOL? Reviewing `dotnet trace` output, I saw: 1.06s (6.3%) Microsoft.Maui.Essentials!Microsoft.Maui.ApplicationModel.AppInfoImplementation.get_RequestedLayoutDirection() 4.46ms (0.03%) Microsoft.Maui.Essentials!Microsoft.Maui.ApplicationModel.AppInfoImplementation.get_RequestedTheme() So approximately 6.3% of the time was spent querying if layouts are RTL or not? And 0.03% checking dark mode? I went through `AppInfoImplementation` on Android, and simply used `Lazy` for every value that queries `Application.Context`. These values cannot change after the app launches, so they don't need to be computed on every call. If these values ever need to match a `Context` for multiple activities, we should re-evaluate this caching. A dictionary using a key of `Context.Handle` might work for that case. We can also remove places with `#if __ANDROID_24__` as they are always true in .NET 6. Runtime checks using `OperatingSystem` should be used going forward. ~~ Results ~~ A `Release` build on a Pixel 5 device, I was getting: Before: 55.42 Dopes/s After: 64.23 Dopes/s This should help the performance of `Label` in any .NET MAUI application running on Android. --- src/Essentials/src/AppInfo/AppInfo.android.cs | 87 ++++++------------- 1 file changed, 27 insertions(+), 60 deletions(-) diff --git a/src/Essentials/src/AppInfo/AppInfo.android.cs b/src/Essentials/src/AppInfo/AppInfo.android.cs index 759918af81e5..5ba26d124130 100644 --- a/src/Essentials/src/AppInfo/AppInfo.android.cs +++ b/src/Essentials/src/AppInfo/AppInfo.android.cs @@ -11,51 +11,21 @@ namespace Microsoft.Maui.ApplicationModel { class AppInfoImplementation : IAppInfo { - public string PackageName => Application.Context.PackageName; + static readonly Lazy _name = new Lazy(() => Application.Context.ApplicationInfo.LoadLabel(Application.Context.PackageManager)); + static readonly Lazy _packageName = new Lazy(() => Application.Context.PackageName); + static readonly Lazy _packageInfo = new Lazy(() => Application.Context.PackageManager.GetPackageInfo(_packageName.Value, PackageInfoFlags.MetaData)); + static readonly Lazy _requestedTheme = new Lazy(GetRequestedTheme); + static readonly Lazy _layoutDirection = new Lazy(GetLayoutDirection); - public string Name - { - get - { - var applicationInfo = Application.Context.ApplicationInfo; - var packageManager = Application.Context.PackageManager; - return applicationInfo.LoadLabel(packageManager); - } - } + public string PackageName => _packageName.Value; + + public string Name => _name.Value; public System.Version Version => Utils.ParseVersion(VersionString); - public string VersionString - { - get - { - var pm = Application.Context.PackageManager; - var packageName = Application.Context.PackageName; - using (var info = pm.GetPackageInfo(packageName, PackageInfoFlags.MetaData)) - { - return info.VersionName; - } - } - } + public string VersionString => _packageInfo.Value.VersionName; - public string BuildString - { - get - { - var pm = Application.Context.PackageManager; - var packageName = Application.Context.PackageName; - using (var info = pm.GetPackageInfo(packageName, PackageInfoFlags.MetaData)) - { -#if __ANDROID_28__ - return PackageInfoCompat.GetLongVersionCode(info).ToString(CultureInfo.InvariantCulture); -#else -#pragma warning disable CS0618 // Type or member is obsolete - return info.VersionCode.ToString(CultureInfo.InvariantCulture); -#pragma warning restore CS0618 // Type or member is obsolete -#endif - } - } - } + public string BuildString => PackageInfoCompat.GetLongVersionCode(_packageInfo.Value).ToString(CultureInfo.InvariantCulture); public void ShowSettingsUI() { @@ -67,40 +37,37 @@ public void ShowSettingsUI() settingsIntent.SetData(global::Android.Net.Uri.Parse("package:" + PackageName)); var flags = ActivityFlags.NewTask | ActivityFlags.NoHistory | ActivityFlags.ExcludeFromRecents; - -#if __ANDROID_24__ if (OperatingSystem.IsAndroidVersionAtLeast(24)) flags |= ActivityFlags.LaunchAdjacent; -#endif settingsIntent.SetFlags(flags); context.StartActivity(settingsIntent); } - public AppTheme RequestedTheme - => (Application.Context.Resources.Configuration.UiMode & UiMode.NightMask) switch - { - UiMode.NightYes => AppTheme.Dark, - UiMode.NightNo => AppTheme.Light, - _ => AppTheme.Unspecified - }; + static AppTheme GetRequestedTheme() => (Application.Context.Resources.Configuration.UiMode & UiMode.NightMask) switch + { + UiMode.NightYes => AppTheme.Dark, + UiMode.NightNo => AppTheme.Light, + _ => AppTheme.Unspecified + }; + + public AppTheme RequestedTheme => _requestedTheme.Value; public AppPackagingModel PackagingModel => AppPackagingModel.Packaged; - public LayoutDirection RequestedLayoutDirection + static LayoutDirection GetLayoutDirection() { - get - { - if (!OperatingSystem.IsAndroidVersionAtLeast(17)) + if (!OperatingSystem.IsAndroidVersionAtLeast(17)) return LayoutDirection.LeftToRight; - var config = Application.Context.Resources?.Configuration; - if (config == null) - return LayoutDirection.Unknown; + var config = Application.Context.Resources?.Configuration; + if (config == null) + return LayoutDirection.Unknown; - return (config.LayoutDirection == Android.Views.LayoutDirection.Rtl) ? LayoutDirection.RightToLeft : - LayoutDirection.LeftToRight; - } + return (config.LayoutDirection == Android.Views.LayoutDirection.Rtl) ? LayoutDirection.RightToLeft : + LayoutDirection.LeftToRight; } + + public LayoutDirection RequestedLayoutDirection => _layoutDirection.Value; } } From a698ac794a69d87654e9a6157ce900d6477ef470 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 13 Jun 2022 22:53:20 -0500 Subject: [PATCH 2/2] Remove IsAndroidVersionAtLeast(17) check Minimum API level is 21 in .NET 6 --- src/Essentials/src/AppInfo/AppInfo.android.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Essentials/src/AppInfo/AppInfo.android.cs b/src/Essentials/src/AppInfo/AppInfo.android.cs index 5ba26d124130..6521624bc594 100644 --- a/src/Essentials/src/AppInfo/AppInfo.android.cs +++ b/src/Essentials/src/AppInfo/AppInfo.android.cs @@ -57,9 +57,6 @@ public void ShowSettingsUI() static LayoutDirection GetLayoutDirection() { - if (!OperatingSystem.IsAndroidVersionAtLeast(17)) - return LayoutDirection.LeftToRight; - var config = Application.Context.Resources?.Configuration; if (config == null) return LayoutDirection.Unknown;