Reputation: 791
I've been testing ReactiveUI for a while now (highly recommend it!) but recently came across a performance issue that I'm not sure if it's due to ReactiveUI itself (given that it seems to rely on reflection for some things) OR the Xamarin.Forms App Shell. There's a distinct delay when changing to a Tab whose content has ReactiveUI bindings, this is more noticeable when running on an emulator but can also be experienced on a real device too (tested on Android 6 and Android 9 devices). Is there a strategy to improve App Shell tab performance? The performance issue is only on the tab's first load. Relevant code below (simplified example based on base App Shell visual studio template):
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 is an "empty" class inheriting from 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()
{
}
}
Upvotes: 0
Views: 1284
Reputation: 16547
Well, I have been giving a lot of my time to the awesome Xamarin Forms Shell and I think that itself is the reason for the performance delay that you are talking about right now.
When you read the Microsoft documents it clearly says:
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.
The good thing is that you can fix this by loading these pages on Demand as you may see here: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/tabs#efficient-page-loading
Basically, This can be accomplished by using the DataTemplate markup extension to convert each ContentPage into a DataTemplate and then setting the result as the ShellContent.ContentTemplate property value.
Upvotes: 3