Xamarin Forms Best Practices
Purpose
The objective
of this Wiki is to describe rules, recommendations, and practices for
developing Xamarin Forms applications.Just like any structure, having a solid foundation is critical. Starting our solution out correctly and implementing good practices from the start makes your day to day life so much easier
Choose
between PCL and Shared Based on need:
There are
really two types of solutions that could be used: Portable and Shared.You want portable. It is more versatile and suffers less from misc. ‘weirdnesses’. Portable will make the structure you saw earlier with the Portable Class Library (PCL).
It is the more widely used solution type and the most recommended one for bunch of reasons, but here are the primary two:
- Almost every single scrap of documentation for the important
things you need to do in a Xamarin Forms app is written for PCL, and
- The conditional compilation logic used in Shared Projects is
messy and annoying. It’s way too “Windows 8” to be honest..
Name
your app packages right away, and name them correctly:
This matters
not-a-bit for Windows, a-lotta bit for Android, and is critical for iOS. Just
commit to yourself to start doing this starting right now, and use the “reverse
domain name” style, such as “com.companyname.appname” even though this naming
convention comes from the Java world. Why? Android and iOS want this, and
Windows doesn’t care, so why not just keep them all happy? If you don’t do this
you will eventually HAVE to do it to get some of the apps into the stores, and
if you wait and do it when you’re ready to submit, you may have to totally redo
archives and provisioning profiles.
Never
try to update all the Xamarin.Android.Support packages that show in NuGet
Package Manager:
This is the
first thing developers typically try and do whenever they can’t get the Android
project in their solution to compile or deploy to the emulator. NEVER. UPDATE.
THEM. You will just mess everything else up, and the version of
these assemblies is NOT the problem with your project.
If
you’re not using Visual Studio Mobile Center you are totally missing out:
Visual Studio
Mobile Center is one of the coolest (and most under-marketed) “almost” brand
new offerings, from Microsoft for managing mobile app development and
development lifecycles. (Mostly) based off the original HockeyApp services,
Mobile Center provides a bunch of services needed by mobile developers, into a
single, integrated product.Here is some of features that the mobile Center can offer:
- Having a service that will automatically build, test, and then
distribute your app, every time you commit a build to GitHub or Team
Services.
- Getting full stack traces and analytics for everything that
happens with your app and users.
- Having your app tested on over 400 devices before it goes
live, while you binge watch Gilmore Girls.
Use
MVVM Model-View-ViewModel Pattern:
Use MVVM and
DON’T create your UI in code-behind. So many examples of using Xamarin Forms,
especially for creating controls, spin up and spit out StackPanels and Labels,
and all kinds of junk via code-behind. Don’t do this.XAML-based development is designed to be used with Model-View-ViewModel (MVVM) patterns.
The Xamarin.Forms developer experience typically involves creating a user interface in XAML, and then adding code-behind that operates on the user interface. As apps are modified, and grow in size and scope, complex maintenance issues can arise. These issues include the tight coupling between the UI controls and the business logic, which increases the cost of making UI modifications, and the difficulty of unit testing such code.
The Model-View-ViewModel (MVVM) pattern helps to cleanly separate the business and presentation logic of an application from its user interface (UI). Maintaining a clean separation between application logic and the UI helps to address numerous development issues and can make an application easier to test, maintain, and evolve. It can also greatly improve code re-use opportunities and allows developers and UI designers to more easily collaborate when developing their respective parts of an app.
There is no MVVM template. There is no MVVM base class. But there are plenty of conventions and plenty of framework candy to help MVVM implementations sail simply. XAML developers love MVVM, in fact, MVVM was invented by the original WPF creators. To that end, MVVM is lightweight, simple, and easy to learn.
Third party libraries:
It’s important to recognize that there are many high-quality, third party libraries out there to help developers build out MVVM solutions (like MVVM Light, nRoute). They are great. And, developers should not hesitate to adopt them if they like. Because I like to type, I tend to write my own similar framework with /just/ the code I need and nothing more. I like that. But the frameworks are fine, too.
The benefits of using the MVVM pattern are as follows:
- If there's an existing model implementation that encapsulates
existing business logic, it can be difficult or risky to change it. In
this scenario, the view model acts as an adapter for the model classes and
enables you to avoid making any major changes to the model code.
- Developers can create unit tests for the view model and the
model, without using the view. The unit tests for the view model can
exercise exactly the same functionality as used by the view.
- The app UI can be redesigned without touching the code,
provided that the view is implemented entirely in XAML. Therefore, a new
version of the view should work with the existing view model.
- Designers and developers can work independently and
concurrently on their components during the development process. Designers
can focus on the view, while developers can work on the view model and
model components.
1.
Avoid enabling and disabling UI elements in the
code-behind. Ensure that view models are responsible for defining logical state
changes that affect some aspects of the view's display, such as whether a
command is available, or an indication that an operation is pending. Therefore,
enable and disable UI elements by binding to view model properties, rather than
enabling and disabling them in code-behind.
2.
Keep the UI responsive with asynchronous
operations. Mobile apps should keep the UI thread unblocked to improve the
user's perception of performance. Therefore, in the view model, use
asynchronous methods for I/O operations and raise events to asynchronously
notify views of property changes.
3.
Centralize data conversions in a conversion
layer. It's also possible to use converters as a separate data conversion layer
that sits between the view model and the view. This can be necessary, for
example, when data requires special formatting that the view model doesn't
provide.
4.
Keep view models and views independent. The
binding of views to a property in a data source should be the view's principal
dependency on its corresponding view model. Specifically, don't reference view
types, such as Button and ListView, from view models. By following the
principles outlined here, view models can be tested in isolation, therefore
reducing the likelihood of software defects by limiting scope.
5.
It is common to create a base View Model. This
can consolidate repetitive logic to a single chunk of code. It can also allow
you inherit into a design-time view model which you reference for the sake of
development but that is unused at runtime. I have also done this – almost every
project.
Project
Structure
Most commonly the PCL/Shared Project Contains the following main folders:
- Views: Contains
all app views and UI Pages
- Models:_ Contains app models
- ViewModels: Contains
app view models
- CustomRenders: Contains
all Custom render interfaces that will be implemented each platform.
- CustomControls: Contains
any custom controls to be reusable through the project
- Converters: Contains
the Data Converters will be used by the Xaml Code.
- Services: Contains
all services used through the application and can be injected by the
DependencyService .. For Example [NavigationService , SQLiteService ,
RestfulService .. etc]
- Icons:
If you’ve done any reading about Xamarin you already know that each platform project needs its images in a special folder.
folder, for example. So, you’re probably wondering why we just made a folder for icons in the PCL project. It’s so we can keep all of our icons in one place, and link references to them in all of the other platform projects. We aren’t going to copy them into the other projects because that just becomes a maintenance problem. Every time the boss says to ‘change the download icon’, you have to be sure to change it in all 5 platforms. In our case, since we will have the actual file in the PCL project and just have reference links in the other projects we only have to change one file in one place one time. see Icon strategy
Dependency
Injection:
Dependency
injection enables decoupling of concrete types from the code that depends on
these types. It typically uses a container that holds a list of registrations
and mappings between interfaces and abstract types, and the concrete types that
implement or extend these types.Autofac facilitates building loosely coupled apps, and provides all of the features commonly found in dependency injection containers, including methods to register type mappings and object instances, resolve objects, manage object lifetimes, and inject dependent objects into constructors of objects it resolves.
Notes:
1.
Dependency injection containers are not always
suitable. Dependency injection introduces additional complexity and
requirements that might not be appropriate or useful to small apps. If a class
does not have any dependencies, or is not a dependency for other types, it
might not make sense to put it in the container. In addition, if a class has a
single set of dependencies that are integral to the type and will never change,
it might not make sense to put it in the container.
2.
Registering and resolving types with a
container has a performance cost because of the container's use of reflection
for creating each type, especially if dependencies are being reconstructed for
each page navigation in the app. If there are many or deep dependencies, the
cost of creation can increase significantly.
Communicating
Between Loosely Coupled Components:
While the
MessagingCenter class permits communication between loosely-coupled classes, it
does not offer the only architectural solution to this issue. For example,
communication between a view model and a view can also be achieved by the
binding engine and through property change notifications. In addition,
communication between two view models can also be achieved by passing data
during navigation. see Misuse
Message Center When using MessaginCenter Consider using immutable payload data. Don't attempt to modify the payload data from within a callback delegate because several threads could be accessing the received data simultaneously. In this scenario, the payload data should be immutable to avoid concurrency errors.
Navigation
Consider
caching pages. Page caching results in memory consumption for views that are
not currently displayed. However, without page caching it does mean that XAML
parsing and construction of the page and its view model will occur every time a
new page is navigated to, which can have a performance impact for a complex
page. For a well-designed page that does not use an excessive number of
controls, the performance should be sufficient. However, page caching might
help if slow page loading times are encountered. See Enterprise Navigation
Validation
Any app that
accepts input from users should ensure that the input is valid.for example, check for input that contains only characters in a particular range, is of a certain length, or matches a particular format. Without validation, a user can supply data that causes the app to fail. Validation enforces business rules, and prevents an attacker from injecting malicious data See Enterprise Validation .
Configuration
Management
Xamarin.Forms
includes a persistent dictionary that can be used to store settings data. This
dictionary can be accessed using the Application.Current.Properties
property,
and any data that's placed into it is saved when the app goes into a sleep
state, and is restored when the app resumes or starts up again. In addition,
the Application class also has a SavePropertiesAsync
method
that allows an app to have its settings saved when required. For more
information about this dictionary. See Configuration Management
Accessing
Remote Data
1.
Client apps should be able to utilize the web
API without knowing how the data or operations that the API exposes are
implemented.
2.
Cache data that's read frequently and that
changes infrequently. This data can be added to the cache on demand the first
time it is retrieved by an app. This means that the app needs to fetch the data
only once from the data store, and that subsequent access can be satisfied by
using the cache.
3.
Think of the cache as a transient data store
that could disappear at any time. Ensure that data is maintained in the
original data store as well as the cache. The chances of losing data are then
minimized if the cache becomes unavailable.
4.
Set a default expiration time when configuring
a cache. Many caches implement expiration, which invalidates data and removes
it from the cache if it's not accessed for a specified period. However, care
must be taken when choosing the expiration period. If it's made too short, data
will expire too quickly and the benefits of caching will be reduced. If it's
made too long, the data risks becoming stale. Therefore, the expiration time
should match the pattern of access for apps that use the data.
5.
Never implement an endless retry mechanism
while calling Api. Use a finite number of retries, or implement the Circuit Breaker pattern to allow a service to
recover.
An app can combine the retry and circuit breaker patterns by using the retry pattern to invoke an operation through a circuit breaker. However, the retry logic should be sensitive to any exceptions returned by the circuit breaker and abandon retry attempts if the circuit breaker indicates that a fault is not transient.
An app can combine the retry and circuit breaker patterns by using the retry pattern to invoke an operation through a circuit breaker. However, the retry logic should be sensitive to any exceptions returned by the circuit breaker and abandon retry attempts if the circuit breaker indicates that a fault is not transient.
Performance
Considerations:
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.
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. Whatever your choice here, just don’t leave a screen empty.
Try always to 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
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.To manage that many densities and that many assets, it’s highly beneficial to use an application such as Sketch and/or Zeplin to generate multiple sizes from a single design source.
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:
<PropertyGroup>
...
<AndroidExplicitCrunch>true</AndroidExplicitCrunch>
</PropertyGroup>You can also create the stream when the page is created, or when the Page.Appearing event fires, and then disposing of the stream when the Page.Disappearing event fires.
When downloading an image for display with the ImageSource.FromUri method, cache the downloaded image by ensuring that the UriImageSource.CachingEnabled property is set to true. For more information, see Working with Images .
For more information, see Optimize Image Resources.
3. Lazy Load Anything You Don’t Need Immediately:
The App.xaml
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.Any resources that are used throughout the application should be stored in the application's resource dictionary to avoid duplication. This will help to reduce the amount of XAML that has to be parsed throughout the application. The following code example shows the
HeadingLabelStyle
resource,
which is used application wide, and so is defined in the application's resource
dictionary:
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Resources.App">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="HeadingLabelStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>However, XAML that's specific to a page shouldn't be included in the app's resource dictionary, as the resources will then be parsed at application startup instead of when required by a page. If a resource is used by a page that's not the startup page, it should be placed in the resource dictionary for that page, therefore helping to reduce the XAML that's parsed when the application starts. The following code example shows the
HeadingLabelStyle
resource, which is only on a single page,
and so is defined in the page's resource dictionary:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Test.HomePage"
Padding="0,20,0,0">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="HeadingLabelStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
...
</ContentPage.Content>
</ContentPage>
For more
information about application resources, see Working with Styles .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.
using Xamarin.Forms.Xaml;
...
[assembly: XamlCompilation
(XamlCompilationOptions.Compile)]
namespace PhotoApp
{
...
}
When you want
to set XAMLC options at the class level, you can!
using Xamarin.Forms.Xaml;
...
[XamlCompilation(XamlCompilationOptions.Compile)]
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.
6. Ahead of Time Compilation (AOT):
AOT is classified 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.

7. 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 .
8. Release IDisposable Resources
The IDisposable interface provides a mechanism for releasing resources. It provides a
Dispose
method that should be implemented to explicitly release
resources. IDisposable is not a
destructor, and should only be implemented in the following circumstances:When the class owns unmanaged resources. Typical unmanaged resources that require releasing include files, streams, and network connections.
When the class owns managed IDisposable resources.
Type consumers can then call the IDisposable.Dispose implementation to free resources when the instance is no longer required. There are two approaches for achieving this:
By wrapping the IDisposable object in a using statement.
By wrapping the call to IDisposable
.Dispose
in
a try/finally
block.Wrapping the IDisposable Object in a
using
StatementThe following code example shows how to wrap an IDisposable object in a using statement:
public void
ReadText(string filename)
{
...
string text;
using (StreamReader reader = new StreamReader(filename))
{
text = reader.ReadToEnd();
}
...
}The StreamReader class implements IDisposable, and the using statement provides a convenient syntax that calls the StreamReader
.Dispose
method on
the StreamReader object
prior to it going out of scope. Within the using block, the StreamReader object is
read-only and cannot be reassigned. The using statement also ensures that the
Dispose method is called even if an exception occurs, as the compiler
implements the intermediate language (IL) for a try/finally block.Wrapping the Call to IDisposable
.Dispose
in a
Try/Finally BlockThe following code example shows how to wrap the call to IDisposable
.Dispose
in
a try/finally
block:
public void
ReadText(string filename)
{
...
string text;
StreamReader
reader = null;
try
{
reader = new StreamReader(filename);
text = reader.ReadToEnd();
}
finally
{
if (reader != null)
{
reader.Dispose();
}
}
...
}The StreamReader class implements IDisposable, and the finally block calls the StreamReader
.Dispose
method to
release the resource.For more information, see IDisposable Interface .
9. Unsubscribe from Events
To prevent memory leaks, events should be unsubscribed from before the subscriber object is disposed of. Until the event is unsubscribed from, the delegate for the event in the publishing object has a reference to the delegate that encapsulates the subscriber's event handler. As long as the publishing object holds this reference, garbage collection will not reclaim the subscriber object memory.
The following code example shows how to unsubscribe from an event:
public class Publisher
{
public event
EventHandler MyEvent;
public void
OnMyEventFires()
{
if (MyEvent != null)
{
MyEvent(this, EventArgs.Empty);
}
}
}
public class Subscriber : IDisposable
{
readonly Publisher publisher;
public Subscriber(Publisher publish)
{
publisher = publish;
publisher.MyEvent += OnMyEventFires;
}
void OnMyEventFires(object sender, EventArgs e)
{
Debug.WriteLine("The publisher notified the subscriber of an event");
}
public void
Dispose()
{
publisher.MyEvent -= OnMyEventFires;
}
}The Subscriber class unsubscribes from the event in its Dispose method.
Reference cycles can also occur when using event handlers and lambda syntax, as lambda expressions can reference and keep objects alive. Therefore, a reference to the anonymous method can be stored in a field and used to unsubscribe from the event, as shown in the following code example:
public class Subscriber : IDisposable
{
readonly Publisher publisher;
EventHandler handler;
public Subscriber(Publisher publish)
{
publisher = publish;
handler = (sender, e) => {
Debug.WriteLine("The publisher notified the subscriber of an event");
};
publisher.MyEvent += handler;
}
public void
Dispose()
{
publisher.MyEvent -= handler;
}
}
The handler
field
maintains the reference to the anonymous method, and is used for event
subscription and unsubscribe.
Layouts
Considerations :
1. Choose the Correct LayoutA layout that's capable of displaying multiple children, but that only has a single child, is wasteful. For example, the following code example shows a
StackLayout
with a
single child:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DisplayImage.HomePage">
<ContentPage.Content>
<StackLayout>
<Image Source="waterfront.jpg"
/>
</StackLayout>
</ContentPage.Content>
</ContentPage>This is wasteful and the StackLayout element should be removed, as shown in the following code example:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DisplayImage.HomePage">
<ContentPage.Content>
<Image Source="waterfront.jpg"
/>
</ContentPage.Content>
</ContentPage>In addition, don't attempt to reproduce the appearance of a specific layout by using combinations of other layouts, as this results in unnecessary layout calculations being performed. For example, don't attempt to reproduce a Grid layout by using a combination of StackLayout instances. The following code example shows an example of this bad practice:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<ContentPage.Content>
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name:"
/>
<Entry Placeholder="Enter your name" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Age:"
/>
<Entry Placeholder="Enter your age" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Occupation:"
/>
<Entry Placeholder="Enter your occupation" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Address:"
/>
<Entry Placeholder="Enter your address" />
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>This is wasteful because unnecessary layout calculations are performed. Instead, the desired layout can be better achieved using a Grid, as shown in the following code example:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<ContentPage.Content>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Label Text="Name:"
/>
<Entry Grid.Column="1" Placeholder="Enter your name" />
<Label Grid.Row="1" Text="Age:"
/>
<Entry Grid.Row="1" Grid.Column="1" Placeholder="Enter your age" />
<Label Grid.Row="2" Text="Occupation:"
/>
<Entry Grid.Row="2" Grid.Column="1" Placeholder="Enter your occupation" />
<Label Grid.Row="3" Text="Address:"
/>
<Entry Grid.Row="3" Grid.Column="1" Placeholder="Enter your address" />
</Grid>
</ContentPage.Content>
</ContentPage>2. If you are using AbsoluteLayout a lot, you’re probably using the wrong platform.
Using AbsoluteLayout is messy and support for layout properties changes with the wind. There are other, better ways to do what you want to do.
3. Enable Layout Compression
Layout compression removes specified layouts from the visual tree, in an attempt to improve page rendering performance. The performance benefit that this delivers varies depending on the complexity of a page, the version of the operating system being used, and the device on which the application is running. However, the biggest performance gains will be seen on older devices. For more information, see Layout Compression.
4. Use Fast Renderers
Fast renderers reduce the inflation and rendering costs of Xamarin.Forms controls on Android by flattening the resulting native control hierarchy. This further improves performance by creating fewer objects, which in turns results in a less complex visual tree, and less memory use. For more information, see Fast Renderers.
5. Reduce Unnecessary Bindings
Don't use bindings for content that can easily be set statically. There is no advantage in binding data that doesn't need to be bound, because bindings aren't cost efficient. For example, setting
Button.Text = "Accept"
has less
overhead than binding Button
.Text to a
ViewModel string
property with value "Accept".6. Optimize Layout Performance
To obtain the best possible layout performance, follow these guidelines:
·
Reduce the depth of layout hierarchies by
specifying Margin property values, allowing the creation of layouts with fewer
wrapping views. For more information, see Margins and Padding.
·
When using a Grid, try to ensure that as few
rows and columns as possible are set to Auto size. Each auto-sized row or
column will cause the layout engine to perform additional layout calculations.
Instead, use fixed size rows and columns if possible. Alternatively, set rows
and columns to occupy a proportional amount of space with the GridUnitType.Star
enumeration value, provided that the parent tree follows these layout
guidelines.
·
Don't set the VerticalOptions and HorizontalOptions properties of
a layout unless required. The default values of LayoutOptions.Fill and LayoutOptions.FillAndExpand
allow for the best layout optimization. Changing these properties has a cost
and consumes memory, even when setting them to the default values.
·
Avoid using a RelativeLayout whenever
possible. It will result in the CPU having to perform significantly more work.
When using an AbsoluteLayout, avoid using the AbsoluteLayout.AutoSize property whenever possible.
When using an AbsoluteLayout, avoid using the AbsoluteLayout.AutoSize property whenever possible.
·
When using a StackLayout, ensure that
only one child is set to LayoutOptions.Expands. This property ensures that the
specified child will occupy the largest space that the StackLayout can give to
it, and it is wasteful to perform these calculations more than once.
·
Don't call any of the methods of the Layout
class, as they result in expensive layout calculations being performed.
Instead, it's likely that the desired layout behavior can be obtained by
setting the TranslationX and TranslationY properties.
Alternatively, subclass the Layout<View> class to achieve the desired
layout behavior.
·
Don't update any Label instances more
frequently than required, as the change of size of the label can result in the
entire screen layout being re-calculated.
·
Don't set the Label.VerticalTextAlignment
property unless required.
Set the LineBreakMode of any Label instances to NoWrap whenever possible.
8. Optimize ListView PerformanceSet the LineBreakMode of any Label instances to NoWrap whenever possible.
When using a ListView control there are a number of user experiences that should be optimized:
Initialization – the time interval starting when the control is created, and ending when items are shown on screen.
Scrolling – the ability to scroll through the list and ensure that the UI doesn't lag behind touch gestures.
Interaction for adding, deleting, and selecting items.
The ListView control requires an application to supply data and cell templates. How this is achieved will have a large impact on the performance of the control. For more information, see ListView Performance .
9. Reduce the Visual Tree Size
Reducing the number of elements on a page will make the page render faster. There are two main techniques for achieving this. The first is to hide elements that aren't visible. The
IsVisible
property
of each element determines whether the element should be part of the visual
tree or not. Therefore, if an element isn't visible because it's hidden behind
other elements, either remove the element or set its IsVisible
property
to false.The second technique is to remove unnecessary elements. For example, the following code example shows a page layout that displays a series of Label elements:
<ContentPage.Content>
<StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Hello"
/>
</StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Welcome
to the App!" />
</StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Downloading
Data..." />
</StackLayout>
</StackLayout>
</ContentPage.Content>
The same page
layout can be maintained with a reduced element count, as shown in the
following code example:
<ContentPage.Content>
<StackLayout Padding="20,20,0,0" Spacing="25">
<Label Text="Hello"
/>
<Label Text="Welcome
to the App!" />
<Label Text="Downloading
Data..." />
</StackLayout>
</ContentPage.Content>
Unit
Testing
Everyone should
be fairly familiar with Unit Testing so I won’t go into many details here. When
doing any MVVM architecture it makes testing the UI code programmatically quite
easy. Unit test against the Model. For each action, the state of the model,
(its properties) should change to what you expect. Simple and easy to test.The only issue is testing PCL’s, which needs certain support. I prefer to use xUnit and if you are just testing the PCL then it works nicely in Visual Studio or their console.
If you need to test in a specific environment, you can use one of their runners. Greg Shackles actually has a create quick start guide for Testing Xamarin Apps with xUnit.
References:
·
Enterprise Application Patterns using Xamarin.Forms
eBook:
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns
·
Red Pill Xamarin
https://redpillxamarin.com/
https://redpillxamarin.com/
·
Xamarin University
https://university.xamarin.com/
https://university.xamarin.com/
·
Xamarin Forms for Windows Developers: Tips,
Tricks and Lessons Learned
https://www.wintellect.com/xamarin-forms-for-windows-developers-tips-tricks-and-lessons-learned-part-1/
https://www.wintellect.com/xamarin-forms-for-windows-developers-tips-tricks-and-lessons-learned-part-2/
https://www.wintellect.com/xamarin-forms-for-windows-developers-tips-tricks-and-lessons-learned-part-1/
https://www.wintellect.com/xamarin-forms-for-windows-developers-tips-tricks-and-lessons-learned-part-2/
·
5 Ways to Boost Xamarin.Forms App Startup Time
https://blog.xamarin.com/5-ways-boost-xamarin-forms-app-startup-time/
https://blog.xamarin.com/5-ways-boost-xamarin-forms-app-startup-time/
·
Xamarin.Forms Performance
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/deploy-test/performance
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/deploy-test/performance
·
14
Days To Building An Enterprise Quality Xamarin Forms App
https://xamarinhelp.com/14-days-to-building-an-enterprise-quality-xamarin-forms-app/
https://xamarinhelp.com/14-days-to-building-an-enterprise-quality-xamarin-forms-app/
ReplyDeleteExcellent Blog, I like your blog and It is very informative. Thank you
xamarin online course
learn xamarin online