Slow startup of xamarin app

2019-05-11 11:37发布

问题:

We are developing a cross platform app on a PCL, but for the time being we are only using android devices for testing.
Our concern is that its taking about 6 to 8 seconds (depending on which device we test it) to start the app, which is very slow.
After placing a few breakpoints we saw that the timing is consumed pretty evenly.
We did notice this particular parts took longer:

  • 1s before reaching onCreate() on MainActivity (there's a splash screen before which only has one image and a background color)
  • 1s on base.OnCreate(bundle);
  • 1s on global::Xamarin.Forms.Forms.Init(this, bundle);
  • 1.5s on Page mainPage = new LogScreen(); (creating the main page to then set it as main navigation page).

回答1:

This is a common problem while using Xamarin.Forms there are many threads related to this specially this one:

https://forums.xamarin.com/discussion/93178/lets-talk-performance/p6

The good news is that the Xamarin team is working on it.

Here are some tips you can do improve it:

https://blog.xamarin.com/5-ways-boost-xamarin-forms-app-startup-time/



回答2:

First thing I would recommend is to not benchmark a debug build of your app, the code paths of the Mono runtime and Jit'd code are not the same as a release build, the use of shared runtimes, assembly sizes, etc, etc, etc. will all effect the startup and execution times.

Here are examples of startup times of a "very large" aggressively tuned Android Forms-based app on high-end and low-end devices using an in-house benchmarker (conditionally compiled in, not injected, and using the OS's system clock).

App Overview:

  • Xamarin.Forms v2.4.0.269-pre2
  • Mix of coded and XAML based Pages, Controls, etc...
  • XAML Compiler enabled
  • "Splash screen" disabled
    • A Theme-based splash on MainActivity will add:
      • 200+ milliseconds to startup times on a fast device,
      • 1-2 seconds on a device w/ slow flash access
    • Just do not use an Activity-based splash-screen ;-)
  • Multi-dex'd
  • Proguard'd (aggressively reduced jars via UI testing w/ auto-feedback loop)
  • Linker (Link All, aggressively reduced assembly sizes with a custom link description file generated via UI testing w/ auto-feedback)
  • 100% source-built to allow collapsing namespaces and assembly reduction
  • Viper architecture w/ no 3rd-party DI/IoC
  • Lazy-loaded design using data, resource ad network priority queues
  • Realm live objects and queries used for all data (DB min. size: 250MB, max. size 1.2GB)

Times are generated via a shell script that reboots the devices, monitors the startup to wait for the system to settle, launches a series of apps (GApps, Facebook, Instagram, Twitter, etc...), waits for the system to settle, and then launches the Forms app via:

export deviceTime=$(echo "$(adb -s $deviceID shell cat /proc/uptime | awk '{print $1}') * 1000" | bc -l)
adb -s $deviceID shell am start -n com.sushihangover.GeneticCancerDNAMapper/com.sushihangover.GeneticCancerDNAMapper.DevOpsDashboard --el startTime ${deviceTime%.*}

Google Pixel (Oreo-based) device (app is usable in ~430ms):

I GeneticCancerDNAMapper: 0.162 : Xamarin.Forms.Platform.Android.FormsAppCompatActivity.OnCreate
I GeneticCancerDNAMapper: 0.164 : Xamarin.Forms.Platform.Android.FormsAppCompatActivity.base.SetTheme
I GeneticCancerDNAMapper: 0.201 : Xamarin.Forms.Platform.Android.FormsAppCompatActivity.base.OnCreate
I GeneticCancerDNAMapper: 0.244 : Xamarin.Forms.Forms.Init
I GeneticCancerDNAMapper: 0.266 : Realms.Realm.GetInstanceAsync ~Get Instance & Data~
I GeneticCancerDNAMapper: 0.324 : Realms.Realm.GetInstanceAsync ~Obtained Instance & Data~
I GeneticCancerDNAMapper: 0.324 : Xamarin.Forms.Application Content
I GeneticCancerDNAMapper: 0.349 : Xamarin.Forms.Application Content ~Creation Completed~
I GeneticCancerDNAMapper: 0.353 : Xamarin.Forms.Application.MainPage ~Displayed~
I GeneticCancerDNAMapper: 0.43 : Xamarin.Forms.Platform.Android.FormsAppCompatActivity.LoadApplication

Low-end "Android One" 512MB device w/ very slow flash (app is usable in ~4.5s):

Re: https://en.wikipedia.org/wiki/Android_One

I/GeneticCancerDNAMapper(10904): 2.453 : Xamarin.Forms.Platform.Android.FormsAppCompatActivity.OnCreate
I/GeneticCancerDNAMapper(10904): 2.467 : Xamarin.Forms.Platform.Android.FormsAppCompatActivity.base.SetTheme
I/GeneticCancerDNAMapper(10904): 2.731 : Xamarin.Forms.Platform.Android.FormsAppCompatActivity.base.OnCreate
I/GeneticCancerDNAMapper(10904): 3.016 : Xamarin.Forms.Forms.Init
I/GeneticCancerDNAMapper(10904): 3.166 : Realms.Realm.GetInstanceAsync ~Get Instance & Data~
I/GeneticCancerDNAMapper(10904): 3.571 : Realms.Realm.GetInstanceAsync ~Obtained Instance & Data~
I/GeneticCancerDNAMapper(10904): 3.571 : Xamarin.Forms.Application Content
I/GeneticCancerDNAMapper(10904): 3.772 : Xamarin.Forms.Application Content ~Creation Completed~
I/GeneticCancerDNAMapper(10904): 3.799 : Xamarin.Forms.Application.MainPage ~Displayed~
I/GeneticCancerDNAMapper(10904): 4.457 : Xamarin.Forms.Platform.Android.FormsAppCompatActivity.LoadApplication


回答3:

I'll put together all the solutions we found for this, so its all in one place.

One of the answers linked this post, which was very useful.

Besides that we also did the following things:

  • Check "optimize code" box on Properties in all projects. Not sure if that improves startup time specifically but it seems to help on the general performance a bit.
  • Add AOT and LLVM. We found a way to do this even though the option isn't available on our IDE. This increases the build time by a lot so if you want to do it I'd recommend doing it only for release builds.
  • Enable Xamarin Fast Renders. This is an experimental thing so you should read some documentation about it, but its done by adding this line global::Xamarin.Forms.Forms.SetFlags("FastRenderers_Experimental"); on MainActivity.OnCreate() method, before global::Xamarin.Forms.Forms.Init(this, bundle);
  • Update our Xamarin.Forms Nuget Version. This needs to be the same version on all projects of your solution, we had some issues with tap gestures which where also improved by this.
  • Link SDK Assemblies. On Properties > Android Options under Linking you can set to link "SDK Assemblies Only". You can also set to all assemblies, but this is not recommended if you are using custom assemblies.
  • Pre-Load screens. This improved by a lot the performance on the app itself what we did is load on each screen, on background, the views and view-models that where needed next, so when pushing them onto the navigation stack they were already loaded. This reduced by a lot the time on transition between pages.