5 Ways to Boost Xamarin.Forms App Startup Time
The Xamarin SDKs for iOS and Android provide an extremely performant foundation upon which to build Xamarin.Forms cross-platform applications. As you work to tune the speed and responsiveness of your Xamarin.Forms application, keep in mind that the same principles that improve the experience of your apps built with the Xamarin SDKs for iOS and Android will also improve those going cross-platform with Xamarin.Forms—and that experience begins at startup.
When you say Startup…
First, let’s define startup as everything that happens from the time the user hits your app icon to when the first usable screen appears ready for business. When you compare a blank Xamarin.Android app with a blank Xamarin.Forms app, you’ll notice the Xamarin.Android app loads quicker. What’s going on?
Xamarin.Forms provides not only the ability to share UI across targets, but common application features such as AppLinks for deep linking, Navigation, MessagingCenter, and DependencyService, as well as several pieces needed for cross-platform UI alerts, action sheets, toolbars, status bars, etc. When you start adding comparable implementations to a Xamarin.Android app, you start to see the difference in performance disappearing. This begins to explain what’s going on, so what’s in your control to impact startup? Here are my top five tips to tune your startup experience across iOS, Android, and UWP targets.
1. Load Local Content First
We often want to load fresh data as soon as our application has launched, but this will only slow down the first screen from appearing and populating. Use state from a previous run or have content ready to go that is for the first run.
If you application is already offline ready, and we recommend it is, then you’re all set to populate the content for your first screen instantly. Azure Mobile Apps and Realm with Azure are great options.
When you must go to the web for your first run content, provide some UI telling the user what you’re doing by using a loading indicator. This is also a perfect opportunity to replace the blank part of your screen with useful placeholder content to reinforce why this screen exists, what the user can expect from the app or just something fun! Whatever your choice here, just don’t leave a screen empty.
Payload Tips Minimize your web payload to just what you need. Don’t spend time on expensive processes like parsing strings, rather deliver your data as it needs to be represented.
2. Optimize Your Assets
Images and video are heavy and can drastically slow down the initial rendering of a screen. Reduce reliance on heavy assets and optimize any media you use for the necessary dimensions. Don’t rely on the OS to resize the assets for you.
For Android target screens, assets are placed in folders representing their density.
- ldpi (low) ~120dpi
- mdpi (medium) ~160dpi
- hdpi (high) ~240dpi
- xhdpi (extra-high) ~320dpi
- xxhdpi (extra-extra-high) ~480dpi
- xxxhdpi (extra-extra-extra-high) ~640dpi
There’s also a special density of
nodpithat tells Android to not scale the resources regardless of screen density.
When you put a large image in the
ldpi folder and use that asset on a screen of
xxhdpi, Android will scale it up. This is slow and will bloat your runtime memory consumption, sometimes even to the point of crashing your application; I’ve done it.
Xamarin.Android 7.0 recently added an experimental option to pre-crunch PNG files called AndroidExplicitCrunch. This further reduces the size of your assets (and application), speeds up build time, and ensures they are optimized for runtime. To enable this, edit the text of your Android
csproj and amend the
PropertyGroup for your build configuration:
3. Lazy Load Anything You Don’t Need Immediately
Resources is a convenient place to put styles, fonts, and other resources that you’ll use throughout your application, but it’s also all loaded at startup. If you’re trying to erase every unnecessary millisecond from your startup time, remove anything here that you don’t need and lazy load it by page or in another method.
4. Enable XAML Compilation
XAML is a popular and expressively powerful way to declare your user interface. If you opt to stay in C# and build your UI there, it’s naturally compiled along with the rest of your code, giving you compile-time checking and speed. When you want that same benefit while using XAML, you enable XAML Compilation (XAMLC). This will compile your XAML into Intermediate Language (IL) and add it to your compiled assembly, resulting in faster startup and runtime performance. Let’s look at how you can enable this:
At the application level, you may declare your XAMLC options and it will impact your entire app.
[assembly: XamlCompilation (XamlCompilationOptions.Compile)]
When you want to set XAMLC options at the class level, you can!
public class HomePage : ContentPage
When XAMLC is enabled you’ll get compile time XAML checking on most all properties and UI will render faster. File size may remain unchanged or grow slightly as you are trading
.xaml file size for IL in the assembly.
5. Reduce Number of Assemblies
Convenience comes at a cost, as usual. It might be a very small cost, but you want to leave no stone unturned when tuning for performance. While NuGet packages are awesome for leveraging other libraries, the reality is that the more (and larger) assemblies your mobile application depends on naturally slows down the execution as calls pass across boundaries. Xamarin.Forms, for example, inspects all assemblies for
[ExportRenderer] attributes and currently has no method to opt-in or opt-out. This is something we’re working to improve.
Weigh the pros/cons of each dependency and, when possible, bring that code into your main application. Your mileage may vary, so give it a look. This is an often overlooked performance consideration that may pay dividends for you.
Bonus 1: Ahead of Time Compilation (AOT)
I’m calling this bonus because we still classify AOT as experimental on Android and it won’t apply to everyone. Of course, iOS uses AOT and the LLVM compiler by default, so there’s nothing to do there.
Enable the experimental Android AOT and get immediate improvement in startup as well as overall speed by reducing some Just-In-Time compilation overhead. The price paid is an increase in the size of your APK, so you should try this out and weigh the pros and cons for your application. To enable AOT, open your project configuration and check the box.
Bonus 2: Build Time Improvements
While not directly applicable to startup improvement, one of our awesome mobile solutions architects Brandon Minnick has shared his collection of build optimization configurations. Check it out on GitHub.
These are just a few of my favorite tips, and they can apply to all screens of your application, not just the startup screen. I could go on about flattening layout, optimizing measuring in layout cycles, and more. Much of that and more is covered in our Xamarin.Forms Performance guide.
The community and Xamarin.Forms engineering team have been trading tips and discussing pain points and possible solutions on the Xamarin Forums. Please join that conversation to share your findings, and follow along as we continue to explore improving startup and runtime performance across all platforms in Xamarin.Forms.