适用于 iOS
和 Android
的 Xamarin SDK
提供了一个非常高性能的基础,以便构建 Xamarin.Forms
跨平台应用程序。当你努力优化 Xamarin.Forms
应用程序的启动速度和响应速度时,请记住,能优化构建在 Xamarin SDK
基础之上的iOS
和 Android
应用的方法 也能优化 Xamarin
跨平台的应用程序。而且这些优化从最开始的启动就起作用。
PS: 即适用于原生
Android
和iOS
的性能优化方法也适用于Xamarin.iOS
和Xamarin.Android
启动时间的定义
首先,让我们将 启动 定义为从用户点击应用图标到第一个界面可见时发生的所有事情。当你对比一个 新建的Xamarin.Android
和 新建的 Xamarin.Forms
项目的时候,你会发现 Xamarin.Android
项目加载的更快一些。这中间发生了什么呢?
Xamarin.Forms
不仅提供跨平台共享的 UI
, 还提供了一些常见的应用功能比如: AppLinks for deep linking, Navigation, MessagingCenter, and DependencyService, 还有一些必要的跨平台的 UI
: alerts
, action sheets
, toolbars
, status bars
, etc.
如果你向 Xamarin.Android
应用程序添加类似的实现时, 你就会看到之前 Xamarin.Android
和 Xamarin.Forms
性能上的差异相差无几了。这就解释了为什么 Xamarin.Forms
app 为什么启动时间会稍长一点,那我们如何来控制 Xamarin.Forms
app 的启动时长呢? 以下是我在 iOS
,Android
和 UWP
targets 中优化 启动时间 的五个建议。
1. 优先加载本地资源
我们通常希望在 应用程序启动后 立即加载最新的数据, 但这会减慢 first screen
appearing
和 populating
的速度(类似:Android Actvity --> OnCreate()
and OnResume()
). Use state from a previous run or have content ready to go that is for the first run.
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.
如果你的 app 可以离线使用的话,我们很推荐这样做。优先加载本地资源,之后立即为你的第一个屏幕填充内容了。Azure Mobile Apps and Realm with Azure 是很好的选择。
当你必须 访问网络 以获取首次运行内容时,你可以提供一些 UI
,比如通过使用 加载指示器 (loading indicator)告诉用户 你的 app 正在做什么。这样一来还可以避免白屏的尴尬:先展示占位符,告诉用户屏幕已经加载出来,现在要去加载数据。
Payload Tips:将你的网络的需求降到最低,不要花时间处理一些耗时的操作,比如解析字符串,而是在需要表示数据时提供数据。
2. 优化 Assets
图像和视频通常会比较大,可能会大幅减慢屏幕的初始渲染速度。减少对 Assets
的依赖,并优化您用于必要 dimensions
的任何 media
文件。不要指望 Android OS 为您调整 Assets
大小。
对于 Android target screens,Assets
放置在表示其 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
还有一个特殊的
nodpi
密度,告诉Android
无论屏幕密度如何都不会 scale the resources 。
当您将较大的 image
放在 ldpi
文件夹中并在 xxhdpi
的屏幕上加载该资源时,Android
会对其进行扩展。
这很慢并且会使增加运行时内存的消耗,有时甚至会导致应用程序崩溃;
要管理那么多的 assets
和 assets
资源,非常建议使用像 Sketch 和 Zeplin 一样的应用来生成适用于多种尺寸屏幕的 资源文件。
Xamarin.Android 7.0 中还出了个实验性的选项 pre-crunch
PNG 文件:AndroidExplicitCrunch.
这进一步减少了 Assets
(和应用程序)的大小,减少了 build time
并对运行时的运行速度也有一定的优化。想要使用这个功能,需要编辑你的 Android
csproj
文件,并修改 build configuration
中的 PropertyGroup
.
<PropertyGroup>
...
<AndroidExplicitCrunch>true</AndroidExplicitCrunch>
</PropertyGroup>
3. 懒加载你不需要的东西 来进行优化
App.xaml
Resources
可以放置 styles
, fonts
或者其它一些你需要在你的 app 中使用的 资源,但这些都是在启动时加载的。所以如果你想 毫秒 级别的减少你的 app 启动时间的话, 那你就去掉 App.xaml
中的这些代码,lazy load it by page or in another method.
4. Enable XAML Compilation
XAML
是一种流行且功能强大的声明用户界面的方式。如果你选择使用 C#
并用 XAML
来构建 UI
的话....
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.
我们来看看如何启用它:
在 application
级别,您可以声明您的 XAMLC
选项,它将影响您的整个应用程序:
using Xamarin.Forms.Xaml;
...
[assembly: XamlCompilation (XamlCompilationOptions.Compile)]
namespace PhotoApp
{
...
}
如果要在 class
级别设置 XAMLC
选项,则可以:
using Xamarin.Forms.Xaml;
...
[XamlCompilation (XamlCompilationOptions.Compile)]
public class HomePage : ContentPage
{
...
}
启用 XAMLC
后,您将获得大多数所有属性的编译时 XAML
检查,UI
将更快地呈现。当您在程序集中交换 IL
的 .xaml
文件大小时,文件大小可能保持不变或略有增长。
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. 减少 Assemblies 的数量
通常情况下便利总是要付出成本的。这可能是一个非常小的成本,但你想全力优化性能时就另说了。通过 NuGet
来引用第三方库虽然简单好用,但实际情况是,当调用跨越 boundaries
时,移动应用程序所依赖的组件越多(越大)自然会降低执行速度。
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.
权衡每个依赖的优缺点,并在可能的情况下将该代码放入你的主应用程序中。这有可能会让你的工作量变大一些,所以你权衡一下吧。这是经常被忽略的一点,但也是可以用来优化 app 性能的一点。
彩蛋 1:预编译 AOT -- Ahead of Time Compilation
之所以叫它彩蛋是因为我们目前还是把 Android
中的 AOT
当作 experimental
的功能来看,而且这不是对所有人都适用。 当然,iOS
里默认使用 AOT
和 LLVM
编译,所以在这也没什么好说的。
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.
VS for Mac 中 开启这个选项:
注意: AOT is available on Xamarin Android 5.1 and 7.0+
彩蛋 2:优化 编译时间 | Build Time Improvements
Xamarin
项目通常比原生的项目会花费更多的 build time, 如何来优化呢?可以参考:关于如何加快编译 Xamarin
应用程序所需时间的提示和技巧
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.
之后怎么优化?
以上只是我比较喜欢的几个建议,而且它们不仅可以优化 app 启动时间。 我可以继续关于 扁平化布局,优化布局周期中的 measuring
和 layout
等来继续深入优化。你可以在 Xamarin.Forms Performance guide 里看到这些内容。
社区 和 Xamarin.Forms
工程师团队一直在 Xamarin Forums (论坛) 讨论一些 Xamarin 的痛点和相应的解决方案。 欢迎大家来加入一起讨论下如何继续优化 Xamarin
的性能。
Link: https://blog.xamarin.com/5-ways-boost-xamarin-forms-app-startup-time/