Posted in: Development and Technology
Tags:

I recently discovered that I can get native speed, smooth scrolling ListViews in Xamarin forms, using XAML for the cells. This goes against the accepted belief that good performance with XAML cells is not possible. In this blog post I explain how I came to my solution, and how you can also achieve great performing lists while enjoying all the benefits that XAML affords you for your ViewCells.

INTRODUCTION

This section is about Xamarin Forms.  If you know what those are, feel free to skip ahead to the next section. Otherwise read on.

Xamarin platform is rapidly gaining traction with their marvelous cross-platform mobile framework and development tools. Last year, they released Xamarin Forms, which facilitates the cross platform development of user interface controls and views, further reducing the amount of platform specific code required for cross platform developers.

As an ex Adobe Flex and current iOS developer, I’ve been extremely impressed with their implementation. Xamarin have thought carefully about pitfalls which many other frameworks fall down, and came up with a solution that generates native platform controls, and therefore native platform performance and “feel”.

You can get more information about Xamarin and Xamarin forms here:

 

XAML or C#: Two approaches for implementing Xamarin Forms views

Xamarin Forms allows us to create “pages”, which can be coded in XAML (an XML-like markup language) or C#. For example, the following list definition could be written as:

C#

var list = new ListView {
 IsGroupingEnabled = true,
  GroupDisplayBinding = new Binding("LongTitle"),
  GroupShortNameBinding = new Binding("Title"), // optional, used for jumplist
  ItemTemplate = new DataTemplate(typeof(TextCell)) {
   Bindings = {
    {
     TextCell.TextProperty,
     new Binding("Name")
    },
    {
     TextCell.DetailProperty,
     new Binding("Description")
    }
   }
  }
};

XAML

<ListView x:Name="itemListView"  IsGroupingEnabled="true"  GroupDisplayBinding="{Binding LongTitle}"  GroupShortNameBinding="{Binding Title}">
        <ListView.ItemTemplate>
                <DataTemplate>
                        <TextCell Text="{Binding Name}" Detail="{Binding Description}" />
                </DataTemplate>
        </ListView.ItemTemplate>
</ListView>

 

I personally favor XAML, as I find it far easier to read and maintain. However, XAML views require parsing at runtime, which can be quite an overhead. At the time of writing, the next Xamarin forms release (1.4.3) has a XAML compiler, for creating pre-compiled XAML, which will greatly help with performance overhead.

 

XAML cells in Listview, the great Xamarin Taboo

I’ve now done a fair bit of Xamarin, and found that performance is not usually an issue for pages or controls, as the XAML is fairly quick to parse. However, this breaks down pretty quickly when using ListViews. We find scrolling artifacts and stuttering with even the most trivial of view cells (e.g. 2 images, and 2 labels, wrapped in an absolute layout). The official stance from Xamarin has always been to say that we should use XAML for only the most trivial of cells, using their off-the-shelf optimized cells where possible (such as image cell, text cell etc.) and drop down to C# the minute we want to do anything complicated, in fact in their documentation, they even suggest using native view cells to get performance improvements.

The forums are also littered with similar advice. Many novice users of Xamarin miss obvious performance enhancements, such as correct image caching and do not understand how to write well optimized view cells, in XAML or otherwise. It’s fair enough; but I’ve seen this advice given to more experienced developers such as myself also, and with good reason, take a look at this performance here (first 21 seconds are Xamarin’s default performance) – it’s shockingly bad:

xaml_video

 

I must state that aside from being extremely ugly, the cell in this video is actually completely contrived and uses XAML which even the noobiest of noobs would be ashamed to demonstrate at ViewCell noob meetup.

Each view cell has:

  • 4 ViewStacks (expensive layout class),
  • 7 images,
  • 3 buttons,
  • 8 labels,
  • 3 text inputs

You would be flat out insane to write a view cell like this; but regardless of what’s in my view cell, I’d still much rather read this as XAML than C#: ComplexFastCell.xaml

Debunking the myth

I’ve already amassed a fairly solid understanding of what Xamarin is doing, and how, and I’ve had 5 years iOS experience. I couldn’t understand what could be causing the drastic performance degradation I was seeing, but accepted it as gospel, as that was the official stance and what was constantly stated in the forums.

Optimizing Xamarin Forms apps

One of the many things that excites me about Xamarin Forms is that the implementation is so smart. There are always options close at hand whenever one needs something more performant or more platform-customized code. We can choose to implement our apps using the following methods:

1. Write a control in
XAML,
2. Write a control using C#,
3. Write it using a native renderer on a given platform,
4. Use an entirely custom view.

I’ve only had to drop down to options 3 a handful of times:

  • Create a highly custom navigation system,
  • Implement a video player control (which is not supported by Xamarin forms),
  • Implement Facebook login (which strictly speaking was very little view code),
I have, however, had to drop down to option 2 many times when I’ve been working with ListViews. As someone new to the platform, and busy learning the many APIs, and idioms, I didn’t think to question the wisdom of the forums, or Xamarin’s own documentation that ”
XAML in view cells, is likely not going to be performant”. However, that all began to change, ironically, once I stopped working with ListView.

Daring to think about XAML performance in ListView

For a project I’m working on, I needed to have a grid view (i.e. native equivalent of UICollectionView). I found one, among many other jewels in the excellent Xamarin Forms Labs project (Xlabs) . However, my GridView is actually quite heavy. The cells in the gridview contain GridViews themselves. It’s certainly a taxing part of the app; but believed it to be possible, after a brief perusal of the XLabs GridView code, combined with a sound understanding of how the decorator/native renderer implementation of Xamarin Forms works.

I was surprised to find that performance was fairly bad. I then set about hacking around and investigating the XLabs GridView project and found that it wasn’t (at least to my mind) correctly implementing their flyweight. As the iOS developers amongst us know, all UICollectionViewCells have a dequeue method to facilitate cell reuse, which is essential to attain good performance (Android users get a reusable view passed into their GetCell delegate methods, if I remember right; but it’s still flyweight pattern).

To my surprise, GridView was only partially doing this. It was reusing a native UICollectionViewCell; but for each item in it’s datasource, was creating a new Xamarin ViewCell. This was immensely costly. I fixed this oversight by adding my own flyweight mechanism (a simple dictionary) and continued on my way, with excellent results.

That experience made me realize that we can get native performance with XAML ViewCells. This was enough to convince me to start challenging the accepted view that Xaml should not be used for ViewCells.

 

 challengeaccepted

What happens when we write XAML code in a Xamarin app?

Xamarin makes smart use of decorator pattern for it’s rendering mechanism. Controls are split into 2 parts. The actual control, and the renderer. The control code lives in the shared project and is available to all platform projects. The renderer has a per-platform implementation, which is responsible for creating, and controlling the native underlying control, which the user sees and interacts with.

When a control is written in XAML, Xamarin forms generates code files at compile time, which add various hooks and other framework calls which will result in parsing the XAML document and instantiating and initializing the views described therein.

Some of these views may be simple controls or aggregate views, such as containers (layouts in Xamarin parlance). The layout views, as one would expect, are expensive to create as they in turn create, measure and layout further children views.

So what’s going on in there?

I’ve already been hacking around with the excellent Mono IL editor/inspector, Mono.Cecil, and am aware of some other blog posts which question the wisdom of Xamarin’s layout mechanisms. I didn’t actually find much joy in that approach, and didn’t want to go down the path of editing dlls or pestering Xamarin. I wanted a solution a client could count on, so an approach which uses off the shelf Xamarin Forms was a must. Identifying the issue was surprisingly and, I must confess, dishearteningly quick (why hasn’t anyone else noticed this?); I didn’t even use the profiler. I simply put breakpoints in the constructors of my FastImage custom view, inside a custom XAML ViewCell, and created a TableView with a few hundred items and scrolled down.

The XAML looked like this:

<?xml version=“1.0“ encoding=“UTF–8“?>
<ViewCell
        xmlns=“http://xamarin.com/schemas/2014/forms“
        xmlns:x=“http://schemas.microsoft.com/winfx/2009/xaml“
x:Class=“TwinTechs.Example.Cells.SimpleViewCell“
        xmlns:controls=“clr–namespace:TwinTechs.Controls;assembly=TwinTechsLib“
>
        <AbsoluteLayout BackgroundColor=“Black“>
                <controls:FastImage x:Name=“ImageView“ AbsoluteLayout.LayoutFlags=“WidthProportional“ AbsoluteLayout.LayoutBounds=“0,0,1,260“/>
                <Label x:Name=“NameLabel“ Text=“Someone“ TextColor=“White“  AbsoluteLayout.LayoutFlags=“None“ FontSize=“Small“  AbsoluteLayout.LayoutBounds=“50,250,100,30“/>           
                <Label x:Name=“DescriptionLabel“ Text=“Description“ TextColor=“White“ AbsoluteLayout.LayoutFlags=“None“ FontSize=“Small“ AbsoluteLayout.LayoutBounds=“50,280,100,40“/>
        </AbsoluteLayout>
</ViewCell>

 

What I was expecting was to see the breakpoint hit maybe 4 times. One for the item template, and 3 more for the number of visible items. I was aghast to find that it was creating a FastImage (and therefore a ViewCell) for each and every item in the list. This is where the performance degradation in their Listview comes from.

I verified this is also the case on android, and then set about fixing it.

Fixing XAML ListView performance issues

The solution is actually very straight forward, and only required a few minor changes.

  • Create a custom ViewCell subclass (FastCell),
  • Create custom renderers for each platform,
  • Implement a flyweight in the renderer to ensure that only a few ViewCells are ever reused, and simply cycle out the BindingContext for each list item, as opposed to creating a new ViewCell for each item
    • On iOS this was very straight forward, and was implemented with a custom native class to wrap the Xamarin ViewCell,
    • On Android (surprise, surprise), it was a bit more involved:
      • I had to move the expensive XAML InitializeCell method, which by default gets invoked on ViewCell instantiation to another method, so I could manage when it got invoked,
      • This forced me to make the FastCell class static, and implement strategy pattern,
      • A cache was necessary, and had to be made available for flushing,

The results of this approach are nothing short of astonishing, remember that first video at the start of the blog post? Here’s the same XAML cells, but using my FastCell implementation. We can see that scrolling is smooth, doesn’t stutter and is so fast that I actually don’t realize I’ve got to the bottom at the end :

xaml_video

I’ve even got another example here which shows that the performance is still there for more (smaller) cells (13 instead of 4, with even more complex/expensive XAML):

 xaml_video_2

Awesome, where can I get it?

The code for the FastCell, and the FastImage are available in our TwinTechsForms library project. We will be updating the project continually, and releasing a nuget package shortly. Follow the project on GitHub to receive updates. We will also look to integrate it with Xamarin Forms.

So what are the limitations of this approach?

I’ve tried this on iOS and Android; but I see no reason why it wouldn’t work on windows platforms.

The code functions as expected with grouped cells, and I’ve also made smaller cells (so there are more on screen) and performance is still pretty indistinguishable from native.

Unfortunately, this technique doesn’t work with Variable row height views. It will not be possible until Xamarin provide an API delegate to allow us to provide row heights without unnecessarily creating ViewCell objects. If you want to see that happen, please speak to your Xamarin account manager and make your voice heard on this issue here.

Also, the lag for creating a page with lots of Cells (like a tablet with lots of rows in a table) can be pretty noticeable – the good news is that Xamarin Forms 1.4.3, with its super XAMLC compiler mitigates this initial lag.

Will Xamarin not just resolve the performance issue themselves?

I’m guessing in time they will visit this; but for now they have stated they have no plans to improve ListView performance or review their O(numberOfDataSourceItems) algorithm for their ViewCell flyweight. Their official line is still “do not create view cells in XAML”. 

I think this is in part because they have a lot of people come into the xamarin platform who don’t really know how to get the most out of it, or what it’s best suited for and then get very upset when it doesn’t do what they want. The fact is that Xamarin Forms is exceptionally powerful (I’ve made some incredibly complex apps using it); but one has to know what one is doing. So Xamarin take the safe route and set expectations low for performance, while highlighting out the flexibility they provide for optimization Forms apps.

Saying that, from the conversations I’ve had, it seems that enough people have now seen this performance is possible with XAML and are also wanting it, so perhaps that will encourage Xamarin to think about putting these optimizations on the roadmap.

The take home

 myth-busted1

Xamarin Forms is an excellent technology, which I’m sure we will be seeing a lot more of. It’s great to know that we can develop apps with native look and feel and performance, for multiple platforms, with the flexibility and ease of XAML. It’s also reassuring to see that, despite not being open source, we have means of peering in, and side-stepping or overcoming performance issues.

Reach out to one of our experts