This is a common issue for many Xamarin.Forms developers, and it is a particular issue with Android. In this post, I will be going through how to boost the startup performance of your Xamarin.Forms on an Android app. I will be comparing this to a native Xamarin.Android app, doing a cold boot, with no other apps or processes running. I will be monitoring the startup times with the Displayed value as detailed in Android Launch-Time performance.
For the first initial tests, I am running on my Windows 10, i7 7700HQ Quad Core, Android Emulator (Android 6.0). Remember these tests are for comparing native to forms, not for actual real device times. However, I also run a few tests at the end on a Samsung S7 (Android 6.0), to get real world device results. ABI was x86 for the emulator, armeabi-v7a for the Samsung.
I have a minimum SDK of 5.0, Lollipop (API 21) and compiling against 7.1, Nougat (API 25), all in Release mode. All other settings will be listed as they are changed per test. Each test is run 3 times and an average is given, to help avoid or single out anomalous data.
The app I am using to test, is the default Xamarin.Android and default Xamarin.Forms app from the Visual Studio templates. They both load one single page.
These tests are all run in the Android Emulator (that comes with Android Studio) on my PC.
Linker – Sdk Assemblies Only
I am setting the linker to Sdk Assemblies only. All other options are default at this point. You might consider this, the starting baseline.
Xamarin.Forms: Avg: 2s 677ms
- 2s 621ms
- 2s 698ms
- 2s 712ms
Xamarin.Android: Avg: 1s 647ms
- 1s 534ms
- 1s 594ms
- 1s 814ms
Things don’t look good for Xamarin.Forms in Android at this point. With Xamarin.Forms, taking a whole second longer to load.
Linker – Sdk And User Assemblies
While we are at it, lets see if changing the linker options makes any difference.
Xamarin.Forms: Avg: 2s 807ms
- 2s 720ms
- 2s 797ms
- 2s 905ms
Xamarin.Android: Avg: 1s 449ms
- 1s 365ms
- 1s 585ms
- 1s 398ms
A bit quicker for native, a bit longer for Xamarin.Forms, which is interesting, but these results are really too close to get much meaning.
Ahead of Time Compilation builds everything upfront, to avoid JIT when first running your app. AOT is available when compiling for Android 5.1 and 7.0+. It is not available for 6.0. It is also marked as experimental in the documentation, but not in VS. I am unsure of whether this is out of date documentation or incorrectly labeled in VS. I have released a few production apps with AOT enabled, and never had any issues with it, hence I am counting AOT as a viable option.
File Size Note: AOT increases the file size of the APK, and this can be quite dramatic. Read Reducing App File Size in Xamarin.Forms to learn how to reduce your app size to be acceptable, while using AOT.
Xamarin.Forms: Avg: 796ms
Xamarin.Android: Avg: 504ms
Here we see an incredible performance boost. Native, however is still taking the lead, but only by roughly 290ms.
Bundle Assemblies into Native Code, with AOT
Ticking the bundle assemblies into Native Code, with AOT still enabled.
Xamarin.Forms: Avg: 840ms
Xamarin.Android: Avg: 711ms
This increases startup time, in both projects. I would recommend leaving this off. Though interesting to note how close these times now are.
I haven’t been using XAMLC yet, so lets leave AOT on, and enable XAMLC in the Xamarin.Forms project.
Xamarin.Forms: Avg: 749ms
You will notice, this is now only 250ms off a native Xamarin.Android project startup time, with AOT enabled.
Samsung Galaxy S7 (SM-G930F)
These following tests, are run on a real device, under armeabi-v7a.
AOT and XAMLC
Just AOT and XAMLC in the Xamarin.Forms project are set.
Xamarin.Forms: Avg: 544ms
Xamarin.Android: Avg: 331ms
Native (Java): Avg: 162ms
I added this in just for comparison. By default an Android app will use AOT, when built for Android 7.0 using Android Studio.
Xamarin.Android continues to win here, but it’s even faster on the device that it was on my laptop. We are only seeing an approximate of 210ms in difference, at this point. Native of course, just wipes the floor with them all. Xamarin.Forms, hence sees a 382ms additional overhead compared to pure native, on an Android App cold start.
AOT, XAMLC and LLVM Optimizing Compiler
I ticked the LLVM Optimizing Compiler for these tests.
Xamarin.Forms: Avg: 1s 307ms
- 1s 309ms
- 1s 329ms
- 1s 283ms
Xamarin.Android: Avg: 585ms
Surprisingly, this increases the startup times quite a bit. I would recommend steering clear of this option, unless there are run-time performance issues that require this.
Real App Startup Times
To put some times in perspective, here are the cold start times of some popular Android applications.
- Netflix: 2.8s
- Facebook: 1.6s
- Instagram: 1s
It’s extremely hard for a cold boot of below 1 second, only a few apps achieve it. Back to our example. This was only a simple, empty app, and it is obvious that a larger app will start to increase in startup times, but it won’t by that much, if you setup your app correctly.
- Don’t wait for data to load, before you load your UI.
- Keep number of dependencies / assemblies to a minimum
- Push anything you can to a background thread, if its not explicitly needed for app startup.
- Lazy load anything and everything you can.
Some app developers complain of massive startup times, sometimes up to 10 seconds or more. I wanted to highlight here, that this is no longer in the realm of Xamarin.Forms startup time, this is now the developers code that is causing these delays. These tips are valid for native and Xamarin.Forms developers.
If you want more tips on how to speed the overall speed of your app, have a look at Xamarin.Forms Performance.
Xamarin.Forms 3.0 Makes It Better
While Xamarin.Forms 3.0 hasn’t dropped yet, expected Q3 2017, the roadmap is public, and it’s clear to see the performance enhancements coming, including reduced renderer times and reduced assemblies, just to name a few. We are only 210ms off matching native performance, and these enhancements are going to close that gap.
Bulk renderer creation
Optimize rendering performance on Android with bulk operations.
Cut down on GPU overdraw for Android
Try to avoid overdraw on Android where possible to improve performance.
LayoutCompression allows multiple layers of Xamarin.Forms layouts to be packed into a single native one.
Fast Renderers for Android
Optimize view renderers to streamline view creation and improve performance. Complete all other UI controls.
Reduce native views created
Cut down on backing native views created for Xamarin.Forms, as noted by Miguel in #42948.
Ship Xamarin.Forms as a single DLL to improve startup performance and assist the linker.
OneTime Binding Mode
A mode to express that a binding only need fire once.
Visual State Manager
Provide a Visual State Manager at the Xamarin.Forms level for managing visual properties of elements across visual states. This will allow developers to control how elements appear when they are disabled, focused, etc.
Deprecation of WP8.0 and 8.1
This will impact startup time in particular.
Xamarin.Forms on Android is not as fast as native Xamarin.Android, and it never will be. Xamarin.Forms will always add some overhead, but it’s certainly not as bad as people keep making it out to be. I will certainly welcome further performance improvements, and am not saying the startup time is perfect, but it’s perfectly acceptable for production level apps, as it stands at the moment. If your app is taking too long to startup in Xamarin, look to implement the improvements suggested.