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 属性 值来实现。