Xamarin.Forms Shell + ReactiveUI 选项卡加载性能(Android)
Xamarin.Forms Shell + ReactiveUI Tab loading performance (on Android)
我已经测试 ReactiveUI 一段时间了(强烈推荐它!)但最近遇到了一个性能问题,我不确定它是否是由于 ReactiveUI 本身(因为它似乎依赖反射来实现)一些东西)或 Xamarin.Forms 应用程序 Shell。切换到内容具有 ReactiveUI 绑定的选项卡时会有明显的延迟,这在模拟器上 运行 时更为明显,但也可以在真实设备上体验(在 Android 6 和 Android 9 台设备)。是否有提高 App Shell 选项卡性能的策略? 性能问题仅出现在选项卡的第一次加载上。下面的相关代码(基于基本应用程序 Shell visual studio 模板的简化示例):
AppShell.Xaml
<?xml version="1.0" encoding="UTF-8"?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:local="clr-namespace:ReactiveXam.Views"
Title="ReactiveXam"
x:Class="ReactiveXam.AppShell"
Visual="Material">
<!-- Your Pages -->
<TabBar>
<Tab Title="Browse" Icon="tab_feed.png">
<ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
</Tab>
<Tab Title="About" Icon="tab_about.png">
<ShellContent ContentTemplate="{DataTemplate local:AboutPage}" />
</Tab>
<Tab Title="Test" Icon="tab_about.png">
<ShellContent ContentTemplate="{DataTemplate local:TestPage}" /> <!-- The relevant tab -->
</Tab>
</TabBar>
</Shell>
TestPage.Xaml(TestPageViewModel 是一个 "empty" class 继承自 ReactiveObject)
<?xml version="1.0" encoding="utf-8" ?>
<rxui:ReactiveContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
xmlns:local="clr-namespace:ReactiveXam.Views"
xmlns:vms="clr-namespace:ReactiveXam.ViewModels"
x:TypeArguments="vms:TestPageViewModel"
x:Class="ReactiveXam.Views.TestPage">
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<local:Exposure />
</StackLayout>
</ContentPage.Content>
</rxui:ReactiveContentPage>
Exposure.Xaml
<?xml version="1.0" encoding="UTF-8"?>
<rxui:ReactiveContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:vms="clr-namespace:ReactiveXam.ViewModels"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:TypeArguments="vms:ExposureViewModel"
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
x:Class="ReactiveXam.Views.Exposure">
<StackLayout>
<Label x:Name="balance" />
<Label x:Name="exposure" />
</StackLayout>
</rxui:ReactiveContentView>
Exposure.xaml.cs
public partial class Exposure : ReactiveContentView<ExposureViewModel>
{
public Exposure()
{
InitializeComponent();
ViewModel = new ExposureViewModel();
// The code below slows down the loading of the tab (~5x slower).
this.WhenActivated((disposable) =>
{
this.OneWayBind(ViewModel, vm => vm.Exposure, v => v.exposure.Text).DisposeWith(disposable);
this.OneWayBind(ViewModel, vm => vm.Balance, v => v.balance.Text).DisposeWith(disposable);
});
}
}
ExposureViewModel
public class ExposureViewModel : ReactiveObject
{
double balance, exposure;
public double Balance
{
get => balance = 500.00d;
set => this.RaiseAndSetIfChanged(ref balance, value);
}
public double Exposure
{
get => exposure = 25.00d;
set => this.RaiseAndSetIfChanged(ref exposure, value);
}
public ExposureViewModel()
{
}
}
好吧,我花了很多时间在很棒的 Xamarin Forms Shell 上,我认为这本身就是您现在谈论的性能延迟的原因。
当您阅读 Microsoft 文档时,它清楚地写着:
In a Shell application, each ContentPage that's a child of a ShellContent object is created during application startup. Adding additional ShellContent objects using this approach will result in additional pages being created during application startup, which can lead to a poor startup experience. However, Shell is also capable of creating pages on demand, in response to navigation. For more information, see Efficient page loading.
好的是,您可以通过按需加载这些页面来解决此问题,您可能会在此处看到:https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/tabs#efficient-page-loading
基本上,这可以通过使用 DataTemplate 标记扩展将每个 ContentPage 转换为 DataTemplate 然后将结果设置为 ShellContent.ContentTemplate 属性 值来实现。
我已经测试 ReactiveUI 一段时间了(强烈推荐它!)但最近遇到了一个性能问题,我不确定它是否是由于 ReactiveUI 本身(因为它似乎依赖反射来实现)一些东西)或 Xamarin.Forms 应用程序 Shell。切换到内容具有 ReactiveUI 绑定的选项卡时会有明显的延迟,这在模拟器上 运行 时更为明显,但也可以在真实设备上体验(在 Android 6 和 Android 9 台设备)。是否有提高 App Shell 选项卡性能的策略? 性能问题仅出现在选项卡的第一次加载上。下面的相关代码(基于基本应用程序 Shell visual studio 模板的简化示例):
AppShell.Xaml
<?xml version="1.0" encoding="UTF-8"?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:local="clr-namespace:ReactiveXam.Views"
Title="ReactiveXam"
x:Class="ReactiveXam.AppShell"
Visual="Material">
<!-- Your Pages -->
<TabBar>
<Tab Title="Browse" Icon="tab_feed.png">
<ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
</Tab>
<Tab Title="About" Icon="tab_about.png">
<ShellContent ContentTemplate="{DataTemplate local:AboutPage}" />
</Tab>
<Tab Title="Test" Icon="tab_about.png">
<ShellContent ContentTemplate="{DataTemplate local:TestPage}" /> <!-- The relevant tab -->
</Tab>
</TabBar>
</Shell>
TestPage.Xaml(TestPageViewModel 是一个 "empty" class 继承自 ReactiveObject)
<?xml version="1.0" encoding="utf-8" ?>
<rxui:ReactiveContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
xmlns:local="clr-namespace:ReactiveXam.Views"
xmlns:vms="clr-namespace:ReactiveXam.ViewModels"
x:TypeArguments="vms:TestPageViewModel"
x:Class="ReactiveXam.Views.TestPage">
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<local:Exposure />
</StackLayout>
</ContentPage.Content>
</rxui:ReactiveContentPage>
Exposure.Xaml
<?xml version="1.0" encoding="UTF-8"?>
<rxui:ReactiveContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:vms="clr-namespace:ReactiveXam.ViewModels"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:TypeArguments="vms:ExposureViewModel"
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
x:Class="ReactiveXam.Views.Exposure">
<StackLayout>
<Label x:Name="balance" />
<Label x:Name="exposure" />
</StackLayout>
</rxui:ReactiveContentView>
Exposure.xaml.cs
public partial class Exposure : ReactiveContentView<ExposureViewModel>
{
public Exposure()
{
InitializeComponent();
ViewModel = new ExposureViewModel();
// The code below slows down the loading of the tab (~5x slower).
this.WhenActivated((disposable) =>
{
this.OneWayBind(ViewModel, vm => vm.Exposure, v => v.exposure.Text).DisposeWith(disposable);
this.OneWayBind(ViewModel, vm => vm.Balance, v => v.balance.Text).DisposeWith(disposable);
});
}
}
ExposureViewModel
public class ExposureViewModel : ReactiveObject
{
double balance, exposure;
public double Balance
{
get => balance = 500.00d;
set => this.RaiseAndSetIfChanged(ref balance, value);
}
public double Exposure
{
get => exposure = 25.00d;
set => this.RaiseAndSetIfChanged(ref exposure, value);
}
public ExposureViewModel()
{
}
}
好吧,我花了很多时间在很棒的 Xamarin Forms Shell 上,我认为这本身就是您现在谈论的性能延迟的原因。
当您阅读 Microsoft 文档时,它清楚地写着:
In a Shell application, each ContentPage that's a child of a ShellContent object is created during application startup. Adding additional ShellContent objects using this approach will result in additional pages being created during application startup, which can lead to a poor startup experience. However, Shell is also capable of creating pages on demand, in response to navigation. For more information, see Efficient page loading.
好的是,您可以通过按需加载这些页面来解决此问题,您可能会在此处看到:https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/tabs#efficient-page-loading
基本上,这可以通过使用 DataTemplate 标记扩展将每个 ContentPage 转换为 DataTemplate 然后将结果设置为 ShellContent.ContentTemplate 属性 值来实现。