@JKay holy cow! That is a ton of packages. I wouldn't be surprised in the least if that is causing a large part of that. AOT can be a pain to setup if it's later in the project for sure. For us we had to use it so we had to go through the pain. It was worth it though. We do a ton of dynamic loading so it wasnt easy. You know what they say about humans, we tend to forget the pain. I will try to startup the way back machine and try to remember some things that made it easy for us if you still want to persue that path.
Are all those packages necessary? I know stupid question but man just seems like alot. We built just about everything in house at the time because alot of the stuff we needed simply didn't exist which I guess worked out in the end but didn't seem so at the time.
I dont think half of them are needed. It just builds up when you install a nuget and it installs a load of dependencies and then you uninstall that dependency it leaves them all behind. I think i'll have to have a look at sorting them out
@DavidOrtinau, is any work being done to queue and rationalize layout requests?
Some of our app screens have a lot of dynamic behaviours - views are being hidden/shown, added/removed based on user interactions. We know all the places that we're causing UI updates, and I've been doing some work trying to cut down layout cycles.
From exploring the Forms source code, I have two suggestions that would make life much easier and faster for this kind of UI case:
Instead of immediately effecting a layout change whenever a property is set (e.g. Text or Visible), rather queue these changes and run a single layout cycle on a timer basis - e.g. every 100ms run a layout cycle on the queue.
So act more like a game with a delayed layout loop.
You could be smart about this queue too, e.g. don't push multiple actions for the same object/property combination and you could probably also rationalize layout to be called "top down" from whatever the top level element is in your queue.
If the above is not an option (and understand it involves a lot of work!), then give us developers some kind of master switch to turn layout execution on and off.
This way we can perform all our desired layout manipulations and tell Xamarin Forms to hold off on all layout attempts until we're done manipulating the visual tree. Once done, we can turn layout back on and request a single layout from the top level.
I've actually implemented something like 1. on our custom code side and it definitely helps.
Have 2. would make our solution much faster again, since I still can't stop various internal layout eventing happening inside Forms at present (well not without hacking source code).
@pauldbau I think you can accomplish what you want in your second case by making a custom layout class that allows you to control when the layout is invalidated and force it on your own.
@DavidOrtinau, adding a timer based pipeline for the UI property setters has been a net positive for us, around a 15% improvement though results are highly variable. We run the timer on a 100ms loop and its pretty smooth to our eyes.
I think it could be much faster if we were to heavily customise the base layout classes to prevent any kind of layout recalculation until we've done pumping all UI calls in a timer cycle.
Have already looked pretty deeply into customer renderers and implemented a number of them for controls and layout classes.
A real blocker on customer renderers has been all the private and internally marked stuff in the base XF classes - it's pretty much impossible to implement a really deep custom layout renderer without copy/pasting all the base class code.
For example, to tint the icon colour on a button, we had to copy the entire ButtonRenderer source code because the SetImage async method (which is where we need to apply the tinting) is private.
Similarly if we want to implement a custom Grid, there's just so much within that class and associated classes that are marked internal/private.
Would be great if most XF base stuff was marked protected instead - let those that want to heavily customise do so
Have already looked pretty deeply into customer renderers and implemented a number of them for controls and layout classes.
A real blocker on customer renderers has been all the private and internally marked stuff in the base XF classes - it's pretty much impossible to implement a really deep custom layout renderer without copy/pasting all the base class code.
For example, to tint the icon colour on a button, we had to copy the entire ButtonRenderer source code because the SetImage async method (which is where we need to apply the tinting) is private.
Similarly if we want to implement a custom Grid, there's just so much within that class and associated classes that are marked internal/private.
Would be great if most XF base stuff was marked protected instead - let those that want to heavily customise do so
The historical fixation with internal and private in XF has been really unhelpful in the past. A truly useful framework would allow access to all of its internals, including the things that its developers don't think are going to be needed by anyone except itself. There are many utility classes used by XF that I've had to copy-and-paste into my code because they're either private or internal and hence inaccessible to my code.
I just had a quick scan of the current code on GitHub and found to my surprise and delight a whole bunch of public interfaces with key functionality in them. Very happy to see this, because it should make the business of creating custom renderers much easier. Custom renderers need to have the ability to access all the same facilities of the framework as the "stock" renderers do.
FWIW I also found some typos/possible bugs:
ITextElement isn't public (unlike all the other interfaces).
Same for IValueConverterProvider.
IControlTemplated seems like a really strange name. I would have preferred IControlTemplate.
IGridController has InvalidateMeasureInernalNonVirtual - looks like it's missing a 't'
Can we please have proper types (not tuples) in ITemplatedItemsList<T>? Item1/Item2 etc are such a clunky mechanism for accessing members of the tuple, and so opaque to users of my code, that I always feel like I've been lazy if I use one instead of a type. <Controversy>They really don't belong in high-quality code IMO.</Controversy>
Really happy to see the direction this is all moving though. It should make not only custom renderers but XF itself much better and easier to work with.
From glancing at Costura.Fody, this seems to just include external assemblies as resources, so that's probably not a real merge (a single assembly that contains all your code) that might help with performance issues. Those embedded assemblies still would have to be loaded, so there might even be a performance hit. I could be misinterpreting what's going on behind the scenes though, haven't used it.
Yes, we have additional 3.0 refactoring planned to standardize the renderer APIs together and across target platforms, as well as further improving the ease of creating custom renderers/layouts.
@DavidDancy I'm curious which utility classes you use most often?
I made a custom renderer for ListView, but had to make my own version of UITableViewSource and plumb it in to the ListViewRenderer because the stock one was private (actually an included class) and couldn't be easily subclassed. I would have thought that UITableViewSource and its Android/Win cousins were prime candidates for a virtualised object in XF.
Android ImageExtensions.ToScaleType. I see this is now public - great.
The entire WebViewRenderer ecosystem. When I needed to subclass the WebViewRenderer to make a secure version that checks the certificates of sites it visits, there were many little helper classes that were either internal or private. I ended up copying all of them. I also had to put the iOS renderer into a container so it would resize properly on device rotation.
The Entry renderer used the IsFocusedPropertyKey to set and read focus. That key was private and so instead of being able to simply subclass the Entry renderer when I needed a variation, I had to make a completely new one from a ViewRenderer. I see that as of 3 August this is now public, which will help a lot. However, the same mechanism exists in the Image object where IsLoadingProperty is connected to an internalIsLoadingPropertyKey. Any Image subclasses are going to have trouble with that.
The GestureRecognizer ecosystem. Please give us a mechanism for attaching our own custom recognizers to the object tree.
The classes in the "administration" part of XF (I didn't copy these - just wanted to use them). I'm thinking specifically of the Platform system and the way that renderers are connected to their virtual objects. I really dislike having to do all that connecting up via attributes; I'd much rather do it with a DI container. Internally it's a kind of DI container anyway - so why not just let people use it like one?
I don't know if this is the case any longer, but I wanted to write a custom renderer for a Cell (especially on iOS to support auto-resizing back when it wasn't supported in XF). However I found that it wasn't possible to only have a renderer for Cell without also needing to replace the whole cell-selection mechanism in the ListView renderer. This in turn meant I had to copy the UITableViewSource because it was an included class and the whole thing ended up being bigger than Ben Hur.
The Image ecosystem. IMO every reference to an Image in XF controls should be an ImageSource but there are many things that are (or used to be) FileImageSource instead (e.g. in the Toolbar). I get the argument about FileImageSource being the sensible default that helps new developers to not shoot themselves in the foot by having lots of images download from the Internet. But what we have currently actively prevents that from even being possible. All that's needed is for the stock control to use a ImageSource and set it up by default as a FileImageSource. Then we could reconfigure it if we need to.
StreamWrapper used in UriImageSource. Any subclasses are going to want to use the same kind of mechanism. Well, they would if they could; UriImageSource is sealed, so I guess the XF version is positively the last word on how a UriImageSource should operate. Supposing we need to have a different caching policy or temporarily stream the image to a file before loading it or run streams in parallel or change the buffer size used in copying the stream or... . I guess it would be better to have a IImageSource and then we could make our own. I'm thinking specifically of SVG.
Toolbar stuff. PrimaryToolbarItem and SecondaryToolbarItem are both sealed, but they contain properties that are needed by NavigationRenderer subclasses.
CellRenderer on iOS has GetRealCell and SetRealCell set to internal. Are we not supposed to subclass CellRenderer at all?
I know that subclassing has fallen out of fashion recently, but it's still a valid design tool. When I come to a framework like XF I'm expecting that it will support either inheritance or composition as its underlying philosophy. Any sealed or internal classes basically prevent inheritance - so if XF has those anywhere, I'm expecting that I'm going to see composition points instead. But XF doesn't (yet) have many composition points, so we're left with subclassing if we want to extend the framework. So we need the XF team to think in terms of "how can this be extended" rather than "how can this be protected".
I'm sorry this has turned into such a long list. But I appreciate your openness and am certainly encouraged by all the changes I've seen in the source even as I compiled my reply here. I think I can understand why so much was internal and sealed before (while respectfully disagreeing with the policy!). It's great that so much of that has since become public or protected and I look forward to that trend continuing.
Regarding my experiences with Xamarin.Forms startup time performance.
I am literally a 'boiled frog' with this framework. I have been developing my app for almost 2 years for now and I cannot afford to throw my work out (but I really wish I could switch painlessly to at least Xamarin.Android to gain startup performance) so I am forced to stay with it.
Initially my app was starting over 22 seconds on dual-core phone and ~14 seconds on quad-core phone. My users thought that this stuff just hung and they killed and then uninstalled my app. I am pretty sure I lose many potential users because of terrible startup time.
To gain performance I started adding views asyncronously in child threads in OnAppearing event. This really did the trick in my case nad reduced startup time by approx 10-20%:
`Task.Run(() => InstantineCustomControl());
private void InstantineCustomControl()
{
if (_customControl == null)
{
_customControl = new MyCustomXamlControl() { Margin = new Thickness(5, 5, 5, 5) };
_customControl .SetBinding(MyCustomXamlControl.IsVisibleProperty, new Binding(nameof(MyViewModel.IsControlVisible)));
I agree that this can't be good for performance, but it's almost necessary for an app that uses netstandard. For instance, I have an app that has:
57 netstandard components
12 "core functionality" components (BCL, .Net.Http, ModernHttp, etc)
9 Xamarin.Android components.
6 SqlLitePCLRaw components
That puts the count to around 85 components just for the foundation of an app.
I agree that this can't be good for performance, but it's almost necessary for an app that uses netstandard. For instance, I have an app that has:
57 netstandard components
12 "core functionality" components (BCL, .Net.Http, ModernHttp, etc)
9 Xamarin.Android components.
6 SqlLitePCLRaw components
That puts the count to around 85 components just for the foundation of an app.
Don't use NetStandard 1.6/1.7.
I'm using 1.4, and I don't need those "stupid" thousands System.* and Microsoft.* nugets.
@NamyslawSzymaniuk I'm using NetStandard 1.4. My project.json file is attached in the spoiler section. This project started about 6 months ago, but there may be a more efficient way to add components now that the transition to NetStandard is further down the road. I had planned on revisiting this project's packages in the near future (once more components have moved over to NetStandard) but I would appreciate any insight on how to make this more efficient.
@DirkWilhelm said: @LyndonHughey in your project.json you have both Autofac and Prism.Unity.Forms. Are you really using two containers?
Good eyes. I looked at implementing Autofac, but decided against it. It is not referenced in code, but was still included as a package. It has been removed.
The entire WebViewRenderer ecosystem. When I needed to subclass the WebViewRenderer to make a secure version that checks the certificates of sites it visits, there were many little helper classes that were either internal or private. I ended up copying all of them. I also had to put the iOS renderer into a container so it would resize properly on device rotation.
What kinda problem you had with the webview rotation? I think I have the same problem.
@ChristianSvrd Basically when the device rotated, the WebView would not adjust its size to match the window's new width and height. There would be some blank space between the edge of the WebView and the edge of the application's window.
The reason was that the WebViewRenderer on iOS was implemented as a UIWebView and some resize commands were missing. I implemented my version as a ViewRenderer<WebView, UIWebView> to match the other view renderers in the Forms suite, and the problem went away.
Could please someone give me any tip why AOT + LLVM compilation does not reduce startup time on my Galaxy A3 2016 and Galaxy S6? Is it possible that AOT and LLVM does not reduce startup time?
My build settings:
Release mode
Bundle assemblies into native code
One APK per selected ABI (I have even tried ARMv8 build and no improvement here as well)
Enable Multi-Dex
Linking SDK only
AOT + LLVM
Before and after enabling AOT + LLVM, startup time of my app on Galaxy A3 2016 and on Galaxy S6 were ~8s and ~7s, so no improvements here in this case.
What could I do to reduce the startup time? This is crucial factor for my app now
I have a lot of hope on improved performance. Particularly with listview component on Android (with Xamarin forms).
Today, I'm using different custom Viewcells (with images, Stacklayout structures etc..) and unfortunately, I have very bad performance on Android. I'm looking for a miracle solution !
It's for an important app. I'll try this new way, but I'm a little disappointed about doing new code in order to use same feature but faster
By the way, if someone has a solution for listview, give a sign
I used a similar trick that @zahikramer used. However in Forms itself.
In Android I do have a SplashActivity before the MainActivity and then in App.cs (Forms) I do the following:
public App()
{
MainPage = new IntroPage(); //A dummy and lightweight page containing the look and feel of the app with a loader
//Fire a task to bootstrap the 'real' app
Task.Factory.Startnew(startApplication);
}
public void startApplication()
{
//My startup logic ...
//Some heavy logic
//Some more here
var page = new Mainpage();
Device.BeginInvokeOnMainThread(() => {
MainPage = page;
});
}
This way the User sees transitions and 'perceives' the application to load 'fast(er)' instead of looking at a splashscreen for over 10 seconds
Very interesting @ReinV !
But you have to go through all the init code to enter 'Forms'. How is the performance?
From 10sec delay how much can you cut to the first 'IntroPage' ?
@marcnegri said:
I have a lot of hope on improved performance. Particularly with listview component on Android (with Xamarin forms).
Today, I'm using different custom Viewcells (with images, Stacklayout structures etc..) and unfortunately, I have very bad performance on Android. I'm looking for a miracle solution !
It's for an important app. I'll try this new way, but I'm a little disappointed about doing new code in order to use same feature but faster
By the way, if someone has a solution for listview, give a sign
This is absolutely a bottleneck for android in xamarin forms. But it is actually not that hard to implement a native listview in android and use that in XF. And the performance is extremely fast, even if you were to be sentenced to death for bad UI code. I do most of my listviews native nowadays (only android).
Startup time 4.4S. In a Chinese Device model ZTE Z958
APK size : 76MB.
To accomplish that I'm using the
Proguard = True
AOT = True,
Link = SDK Only
LLVM = True
Maybe I could go further, and get one second less, what would be just great, but when I turn the LLVM to false(Adam suggestion), The app after deployed crashes immediately right after it shows the splash.
Also, the APK gets even smaller if I pass those extra args
no-write-symbols,nodebug
APK size 40MB, but once more the APP crashes as before.
For now, 4.4s in a not so good device, will suffice.
Ps:
The App has 130 Dependecies, counting with System and all plugins
Some feature:
Map,
Chat,
PushNotification.
@ClaudioPereira Just wanted to verify, we have been using those exact settings since they were in working order and have seen the same speeds for awhile now.
@BradChase.2654 said: @ClaudioPereira Just wanted to verify, we have been using those exact settings since they were in working order and have seen the same speeds for awhile now.
Glad to know that wasn't a fluke.
I reviewed some of my code at OnCreate, and the App class, I could get down the other second I was looking for:
My startup time got down to 3.6sec. (Same device ZTE Z958).
Also, tracked down what was causing the crash once I set LVVM=false. and I didn't noticed any improvement in performance though. Same 3.6sec. but I noticed with LVVM=True, the APK grows 2MB.
On the other hand, after fix the crashs at startup time. the additional AOT flag:
That reduced the APK
From 76MB to 58MB.(I think that less then that, only if I got the Liking "SDK and User Assemblies" working properly. what seems the right thing to do)
I'll keep doing some more testing. hopefuly with that settings, my Xamarin.forms app won't do so bad, during startup time.
Posts
Are all those packages necessary? I know stupid question but man just seems like alot. We built just about everything in house at the time because alot of the stuff we needed simply didn't exist which I guess worked out in the end but didn't seem so at the time.
I dont think half of them are needed. It just builds up when you install a nuget and it installs a load of dependencies and then you uninstall that dependency it leaves them all behind. I think i'll have to have a look at sorting them out
For a lot of assemblies I can recommend Fody.Costura :
https://nuget.org/packages/Costura.Fody
tech.trailmax.info/2014/01/bundling-all-your-assemblies-into-one-or-alternative-to-ilmerge/
manuelmeyer.net/2016/01/net-power-tip-10-merging-assemblies/
But be careful when using it with AOT
@zahikramer does Costura.Fody work with xamarin?
Yes @DH_HA1 , tested it and working!
@zahikramer Did this improve load time at all?
@PhilipGruebele Not sure about that....
@DavidOrtinau, is any work being done to queue and rationalize layout requests?
Some of our app screens have a lot of dynamic behaviours - views are being hidden/shown, added/removed based on user interactions. We know all the places that we're causing UI updates, and I've been doing some work trying to cut down layout cycles.
From exploring the Forms source code, I have two suggestions that would make life much easier and faster for this kind of UI case:
Instead of immediately effecting a layout change whenever a property is set (e.g. Text or Visible), rather queue these changes and run a single layout cycle on a timer basis - e.g. every 100ms run a layout cycle on the queue.
So act more like a game with a delayed layout loop.
You could be smart about this queue too, e.g. don't push multiple actions for the same object/property combination and you could probably also rationalize layout to be called "top down" from whatever the top level element is in your queue.
If the above is not an option (and understand it involves a lot of work!), then give us developers some kind of master switch to turn layout execution on and off.
This way we can perform all our desired layout manipulations and tell Xamarin Forms to hold off on all layout attempts until we're done manipulating the visual tree. Once done, we can turn layout back on and request a single layout from the top level.
I've actually implemented something like 1. on our custom code side and it definitely helps.
Have 2. would make our solution much faster again, since I still can't stop various internal layout eventing happening inside Forms at present (well not without hacking source code).
@zahikramer did it improve app responsiveness?
@DH80 , @PhilipGruebele , It's working, but i didn't check it thoroughly.
I didn't see much improvement , but more research need to be done.
@pauldbau I think you can accomplish what you want in your second case by making a custom layout class that allows you to control when the layout is invalidated and force it on your own.
https://developer.xamarin.com/guides/xamarin-forms/user-interface/layouts/custom/
For that matter, it's probably fundamentally what you've done to accomplish your first case.
How is your timer solution working out for you? Can you share some results in terms of layout performance, responsiveness?
@DavidOrtinau, adding a timer based pipeline for the UI property setters has been a net positive for us, around a 15% improvement though results are highly variable. We run the timer on a 100ms loop and its pretty smooth to our eyes.
I think it could be much faster if we were to heavily customise the base layout classes to prevent any kind of layout recalculation until we've done pumping all UI calls in a timer cycle.
Have already looked pretty deeply into customer renderers and implemented a number of them for controls and layout classes.
A real blocker on customer renderers has been all the private and internally marked stuff in the base XF classes - it's pretty much impossible to implement a really deep custom layout renderer without copy/pasting all the base class code.
For example, to tint the icon colour on a button, we had to copy the entire ButtonRenderer source code because the SetImage async method (which is where we need to apply the tinting) is private.
Similarly if we want to implement a custom Grid, there's just so much within that class and associated classes that are marked internal/private.
Would be great if most XF base stuff was marked protected instead - let those that want to heavily customise do so
@DavidOrtinau There are a few of us who have been saying this for years:
The historical fixation with
internal
andprivate
in XF has been really unhelpful in the past. A truly useful framework would allow access to all of its internals, including the things that its developers don't think are going to be needed by anyone except itself. There are many utility classes used by XF that I've had to copy-and-paste into my code because they're eitherprivate
orinternal
and hence inaccessible to my code.I just had a quick scan of the current code on GitHub and found to my surprise and delight a whole bunch of
public
interfaces with key functionality in them. Very happy to see this, because it should make the business of creating custom renderers much easier. Custom renderers need to have the ability to access all the same facilities of the framework as the "stock" renderers do.FWIW I also found some typos/possible bugs:
ITextElement
isn'tpublic
(unlike all the other interfaces).IValueConverterProvider
.IControlTemplated
seems like a really strange name. I would have preferredIControlTemplate
.IGridController
hasInvalidateMeasureInernalNonVirtual
- looks like it's missing a 't'ITemplatedItemsList<T>
? Item1/Item2 etc are such a clunky mechanism for accessing members of the tuple, and so opaque to users of my code, that I always feel like I've been lazy if I use one instead of a type.<Controversy>
They really don't belong in high-quality code IMO.</Controversy>
Really happy to see the direction this is all moving though. It should make not only custom renderers but XF itself much better and easier to work with.
From glancing at Costura.Fody, this seems to just include external assemblies as resources, so that's probably not a real merge (a single assembly that contains all your code) that might help with performance issues. Those embedded assemblies still would have to be loaded, so there might even be a performance hit. I could be misinterpreting what's going on behind the scenes though, haven't used it.
@PhilippSumi , this is why it needs more research.
If anyone has numbers before and after....
@pauldbau @DavidDancy
Yes, we have additional 3.0 refactoring planned to standardize the renderer APIs together and across target platforms, as well as further improving the ease of creating custom renderers/layouts.
@DavidDancy I'm curious which utility classes you use most often?
Do you need to have both AOT and LLVM turned on to see an improvement or just AOT?
AOT is enought to see the difference
@NamyslawSzymaniuk Thanks for the reply.
@DavidOrtinau There are a few:
ListView
, but had to make my own version ofUITableViewSource
and plumb it in to theListViewRenderer
because the stock one was private (actually an included class) and couldn't be easily subclassed. I would have thought thatUITableViewSource
and its Android/Win cousins were prime candidates for a virtualised object in XF.ImageExtensions.ToScaleType
. I see this is nowpublic
- great.WebViewRenderer
ecosystem. When I needed to subclass theWebViewRenderer
to make a secure version that checks the certificates of sites it visits, there were many little helper classes that were eitherinternal
orprivate
. I ended up copying all of them. I also had to put the iOS renderer into a container so it would resize properly on device rotation.Entry
renderer used theIsFocusedPropertyKey
to set and read focus. That key wasprivate
and so instead of being able to simply subclass theEntry
renderer when I needed a variation, I had to make a completely new one from aViewRenderer
. I see that as of 3 August this is nowpublic
, which will help a lot. However, the same mechanism exists in theImage
object whereIsLoadingProperty
is connected to aninternal
IsLoadingPropertyKey
. AnyImage
subclasses are going to have trouble with that.GestureRecognizer
ecosystem. Please give us a mechanism for attaching our own custom recognizers to the object tree.Platform
system and the way that renderers are connected to their virtual objects. I really dislike having to do all that connecting up via attributes; I'd much rather do it with a DI container. Internally it's a kind of DI container anyway - so why not just let people use it like one?Cell
(especially on iOS to support auto-resizing back when it wasn't supported in XF). However I found that it wasn't possible to only have a renderer forCell
without also needing to replace the whole cell-selection mechanism in theListView
renderer. This in turn meant I had to copy theUITableViewSource
because it was an included class and the whole thing ended up being bigger than Ben Hur.Image
ecosystem. IMO every reference to anImage
in XF controls should be anImageSource
but there are many things that are (or used to be)FileImageSource
instead (e.g. in theToolbar
). I get the argument aboutFileImageSource
being the sensible default that helps new developers to not shoot themselves in the foot by having lots of images download from the Internet. But what we have currently actively prevents that from even being possible. All that's needed is for the stock control to use aImageSource
and set it up by default as aFileImageSource
. Then we could reconfigure it if we need to.StreamWrapper
used inUriImageSource
. Any subclasses are going to want to use the same kind of mechanism. Well, they would if they could;UriImageSource
issealed
, so I guess the XF version is positively the last word on how aUriImageSource
should operate. Supposing we need to have a different caching policy or temporarily stream the image to a file before loading it or run streams in parallel or change the buffer size used in copying the stream or... . I guess it would be better to have aIImageSource
and then we could make our own. I'm thinking specifically of SVG.PrimaryToolbarItem
andSecondaryToolbarItem
are bothsealed
, but they contain properties that are needed byNavigationRenderer
subclasses.CellRenderer
on iOS hasGetRealCell
andSetRealCell
set tointernal
. Are we not supposed to subclassCellRenderer
at all?I know that subclassing has fallen out of fashion recently, but it's still a valid design tool. When I come to a framework like XF I'm expecting that it will support either inheritance or composition as its underlying philosophy. Any
sealed
orinternal
classes basically prevent inheritance - so if XF has those anywhere, I'm expecting that I'm going to see composition points instead. But XF doesn't (yet) have many composition points, so we're left with subclassing if we want to extend the framework. So we need the XF team to think in terms of "how can this be extended" rather than "how can this be protected".I'm sorry this has turned into such a long list. But I appreciate your openness and am certainly encouraged by all the changes I've seen in the source even as I compiled my reply here. I think I can understand why so much was
internal
andsealed
before (while respectfully disagreeing with the policy!). It's great that so much of that has since becomepublic
orprotected
and I look forward to that trend continuing.Hello
Regarding my experiences with Xamarin.Forms startup time performance.
I am literally a 'boiled frog' with this framework. I have been developing my app for almost 2 years for now and I cannot afford to throw my work out (but I really wish I could switch painlessly to at least Xamarin.Android to gain startup performance) so I am forced to stay with it.
Initially my app was starting over 22 seconds on dual-core phone and ~14 seconds on quad-core phone. My users thought that this stuff just hung and they killed and then uninstalled my app. I am pretty sure I lose many potential users because of terrible startup time.
To gain performance I started adding views asyncronously in child threads in OnAppearing event. This really did the trick in my case nad reduced startup time by approx 10-20%:
`Task.Run(() => InstantineCustomControl());
private void InstantineCustomControl()
{
if (_customControl == null)
{
_customControl = new MyCustomXamlControl() { Margin = new Thickness(5, 5, 5, 5) };
_customControl .SetBinding(MyCustomXamlControl.IsVisibleProperty, new Binding(nameof(MyViewModel.IsControlVisible)));
I hope this trick helps you a bit
And then I have enabled AOT with LLVM, as suggested here.
My startup times after async views initializing are as follows:
Regular Release build:
Samsung Galaxy S3 Mini: ~16s
Samsung Galaxy Grand Prime: ~11s
Samsung Galaxy A3 2016: ~8s
Samsung Galaxy S6 Edge: ~7s
AOT + LLVM Release build, each eABI in different APK:
Samsung Galaxy S3 Mini: ~6s (MASSIVE improvement here)
Samsung Galaxy Grand Prime: ~5s (MASSIVE improvement here)
Samsung Galaxy A3 2016: ~8s (no change)
Samsung Galaxy S6 Edge: ~7s (no change)
Apps were uninstalled on all devices before updated with AOT + LLVM build. However, Galaxy A3 received update through Google Play beta app.
Could please somebody explain me what happened here? Why and how it is possible that now my low-end devices outperforms higher-end ones?
Thank you for any advice
I agree that this can't be good for performance, but it's almost necessary for an app that uses netstandard. For instance, I have an app that has:
57 netstandard components
12 "core functionality" components (BCL, .Net.Http, ModernHttp, etc)
9 Xamarin.Android components.
6 SqlLitePCLRaw components
That puts the count to around 85 components just for the foundation of an app.
Don't use NetStandard 1.6/1.7.
I'm using 1.4, and I don't need those "stupid" thousands System.* and Microsoft.* nugets.
@LyndonHughey This is pretty much my situation.
I don't have a very good understanding of what NetStandard is, so I couldn't even tell you what version I am using.
but the majority of my libs are
Microsoft.*
andSystem.*
I have no idea if I need them all or what they are even doing.and then a handful of Xamarin libs. Then about 20 actual Third party components that I explicitly installed
@NamyslawSzymaniuk I'm using NetStandard 1.4. My project.json file is attached in the spoiler section. This project started about 6 months ago, but there may be a more efficient way to add components now that the transition to NetStandard is further down the road. I had planned on revisiting this project's packages in the near future (once more components have moved over to NetStandard) but I would appreciate any insight on how to make this more efficient.
{
"supports": {},
"dependencies": {
"Acr.UserDialogs": "6.3.10",
"Answers": "1.4.0",
"Autofac": "4.6.0",
"AutoMapper": "6.0.2",
"Behaviors.Forms": "1.1.0",
"CommonServiceLocator": "1.3.0",
"Crashlytics": "1.4.0",
"ExifLib.PCL": "1.0.1",
"Fabric": "1.4.0",
"Fody": "2.1.0",
"FreshEssentials": "2.1.3",
"Microsoft.Azure.Mobile.Client.SQLiteStore": "4.0.0",
"Microsoft.Bcl": "1.1.10",
"Microsoft.Bcl.Async": "1.0.168",
"Microsoft.Bcl.Build": "1.0.21",
"Microsoft.CSharp": "4.3.0",
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.NETCore.Portable.Compatibility": "1.0.2",
"Microsoft.Win32.Primitives": "4.3.0",
"NETStandard.Library": "1.6.1",
"Newtonsoft.Json": "10.0.3",
"Plugin.Fingerprint": "1.4.4",
"Prism.Core": "6.3.0",
"Prism.Forms": "6.3.0",
"Prism.Unity.Forms": "6.3.0",
"PropertyChanged.Fody": "2.1.3",
"Refractored.MvvmHelpers": "1.3.0",
"Rg.Plugins.Popup": "1.0.4",
"sameerIOTApps.Plugin.SecureStorage": "1.2.2",
"Splat": "1.6.2",
"sqlite-net": "1.0.8",
"SQLite.Net-PCL": "3.1.1",
"SQLite.Net.Async-PCL": "3.1.1",
"SQLite.Net.Core-PCL": "3.1.1",
"SQLitePCL": "3.8.7.2",
"Syncfusion.Xamarin.SfCalendar": "15.2.0.46",
"Syncfusion.Xamarin.SfChart": "15.2.0.46",
"Syncfusion.Xamarin.SfGauge": "15.2.0.46",
"Syncfusion.Xamarin.SfListView": "15.2.0.46",
"System.Collections.NonGeneric": "4.3.0",
"System.Diagnostics.TraceSource": "4.3.0",
"System.Net.Http": "4.3.2",
"System.Net.NetworkInformation": "4.3.0",
"System.Net.Requests": "4.3.0",
"System.Net.Security": "4.3.1",
"System.Net.WebHeaderCollection": "4.3.0",
"System.Runtime.Serialization.Primitives": "4.3.0",
"System.Security.SecureString": "4.3.0",
"Toasts.Forms.Plugin": "3.2.0",
"Toasts.Forms.Plugin-PCL": "3.1.4",
"Xam.Plugin.Connectivity": "3.0.1",
"Xam.Plugins.Settings": "3.0.1",
"Xamarin.Build.Download": "0.4.6",
"Xamarin.Forms": "2.3.5.253-pre5"
},
"frameworks": {
"netstandard1.4": {
"imports": "portable-win+net45+wp8+win81+wpa8"
}
}
}
@JKay You can check your project.json folder (located in the base of your PCL folder) to see what version you're using if you're using it.
@LyndonHughey in your project.json you have both Autofac and Prism.Unity.Forms. Are you really using two containers?
Good eyes. I looked at implementing Autofac, but decided against it. It is not referenced in code, but was still included as a package. It has been removed.
What kinda problem you had with the webview rotation? I think I have the same problem.
@ChristianSvrd Basically when the device rotated, the
WebView
would not adjust its size to match the window's new width and height. There would be some blank space between the edge of theWebView
and the edge of the application's window.The reason was that the
WebViewRenderer
on iOS was implemented as aUIWebView
and some resize commands were missing. I implemented my version as aViewRenderer<WebView, UIWebView>
to match the other view renderers in the Forms suite, and the problem went away.It's still implemented as a
UIWebView
but this problem does not exist in the latest versions of Forms AFAIK (https://bugzilla.xamarin.com/show_bug.cgi?id=30047).Hello again
Could please someone give me any tip why AOT + LLVM compilation does not reduce startup time on my Galaxy A3 2016 and Galaxy S6? Is it possible that AOT and LLVM does not reduce startup time?
My build settings:
Before and after enabling AOT + LLVM, startup time of my app on Galaxy A3 2016 and on Galaxy S6 were ~8s and ~7s, so no improvements here in this case.
What could I do to reduce the startup time? This is crucial factor for my app now
Many thanks for any tips
Best regards
My solution for Android slow startup time WITHOUT AOT is Dual SplashScreen.
You can virtually say that the startup time is cut by half.
Check it out.
I have a lot of hope on improved performance. Particularly with listview component on Android (with Xamarin forms).
Today, I'm using different custom Viewcells (with images, Stacklayout structures etc..) and unfortunately, I have very bad performance on Android. I'm looking for a miracle solution !
It's for an important app. I'll try this new way, but I'm a little disappointed about doing new code in order to use same feature but faster
By the way, if someone has a solution for listview, give a sign
I used a similar trick that @zahikramer used. However in Forms itself.
In Android I do have a SplashActivity before the MainActivity and then in App.cs (Forms) I do the following:
This way the User sees transitions and 'perceives' the application to load 'fast(er)' instead of looking at a splashscreen for over 10 seconds
Very interesting @ReinV !
But you have to go through all the init code to enter 'Forms'. How is the performance?
From 10sec delay how much can you cut to the first 'IntroPage' ?
I did not benchmark it, but the 'perceived' speed gain was pretty good in our application
We had some pretty gnarly setup,
This all took some time, especially on Android, all this now happens in the background.
If I have the time I'll try to benchmark it. We (my bosses / clients) were happy with the improvements
If I could take a guess:
3-4 seconds to the Intro Page
2-3 seconds to the actual Page
This is absolutely a bottleneck for android in xamarin forms. But it is actually not that hard to implement a native listview in android and use that in XF. And the performance is extremely fast, even if you were to be sentenced to death for bad UI code. I do most of my listviews native nowadays (only android).
I'd like to share the results I got after following that thread, and after some googling.
Before, My android App was starting hardly at 12s.
The Size of the APK 60MB.
That post put me in right path:https://xamarinhelp.com/improving-xamarin-forms-startup-performance/ By: Adam Pedley
Adam addressed the AOT, end with an other post he addressed the APK size: https://xamarinhelp.com/reducing-app-file-size-xamarin-forms/
My results after:
Startup time 4.4S. In a Chinese Device model ZTE Z958
APK size : 76MB.
To accomplish that I'm using the
Proguard = True
AOT = True,
Link = SDK Only
LLVM = True
Maybe I could go further, and get one second less, what would be just great, but when I turn the LLVM to false(Adam suggestion), The app after deployed crashes immediately right after it shows the splash.
Also, the APK gets even smaller if I pass those extra args
no-write-symbols,nodebug
APK size 40MB, but once more the APP crashes as before.
For now, 4.4s in a not so good device, will suffice.
Ps:
The App has 130 Dependecies, counting with System and all plugins
Some feature:
Map,
Chat,
PushNotification.
Cheers.
@ClaudioPereira Just wanted to verify, we have been using those exact settings since they were in working order and have seen the same speeds for awhile now.
Glad to know that wasn't a fluke.
I reviewed some of my code at OnCreate, and the App class, I could get down the other second I was looking for:
My startup time got down to 3.6sec. (Same device ZTE Z958).
Also, tracked down what was causing the crash once I set LVVM=false. and I didn't noticed any improvement in performance though. Same 3.6sec. but I noticed with LVVM=True, the APK grows 2MB.
On the other hand, after fix the crashs at startup time. the additional AOT flag:
AndroidAotAdditionalArguments: no-write-symbols,nodebug
That reduced the APK
From 76MB to 58MB.(I think that less then that, only if I got the Liking "SDK and User Assemblies" working properly. what seems the right thing to do)
I'll keep doing some more testing. hopefuly with that settings, my Xamarin.forms app won't do so bad, during startup time.
Here my whole release settings:

Cheers