xamarin 应用程序启动缓慢

Slow startup of xamarin app

我们正在 PCL 上开发跨平台应用程序,但目前我们只使用 android 台设备进行测试。
我们担心的是,它需要大约 6 到 8 秒(取决于我们测试的设备)来启动应用程序,这非常慢。
放置几个断点后,我们看到时间消耗相当均匀。
我们确实注意到这个特定部分花费了更长的时间:

这是使用时的常见问题 Xamarin.Forms 有很多与此相关的线程,特别是这个:

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

好消息是 Xamarin 团队正在努力。

以下是您可以改进它的一些技巧:

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

我建议的第一件事是不要对应用程序的调试版本进行基准测试,Mono 运行时和 Jit 代码的代码路径与发布版本不同,共享运行时的使用,程序集大小等等等等都会影响启动和执行时间。

以下是 "very large" 积极调整的 Android 基于表单的应用程序在高端和低端设备上的启动时间示例,使用内部基准测试程序(有条件地编译,而不是注入,并使用 OS 的系统时钟)。

应用概览:

  • Xamarin.Forms v2.4.0.269-pre2
  • 混合编码和 XAML 基于页面、控件等...
  • XAML 编译器已启用
  • "Splash screen" 禁用
    • MainActivity 上基于主题的启动将添加:
      • 在快速设备上启动时间超过 200 毫秒,
      • 在具有慢速闪存访问的设备上需要 1-2 秒
    • 只是不要使用基于 Activity 的闪屏 ;-)
  • 多索引
  • Proguard'd(通过 UI 带有自动反馈循环的测试积极减少了 jar)
  • Linker(Link 所有,使用通过 UI 自动反馈测试生成的自定义 link 描述文件积极减小组件尺寸)
  • 100% 源代码构建以允许折叠命名空间和程序集缩减
  • 没有第 3 方的 Viper 架构 DI/IoC
  • 使用数据、资源广告网络优先级队列的延迟加载设计
  • Realm 实时对象和用于所有数据的查询(数据库最小大小:250MB,最大大小 1.2GB)

时间是通过 shell 脚本生成的,该脚本会重启设备、监控启动以等待系统稳定、启动一系列应用程序(GApps、Facebook、Instagram、Twitter 等... ), 等待系统稳定下来,然后通过以下方式启动 Forms 应用程序:

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

Google Pixel(基于 Oreo 的)设备(应用可在 ~430 毫秒内使用):

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

低端 "Android One" 512MB 设备,带 非常慢 闪存(应用程序可在 ~4.5 秒内使用):

回复: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

我会把我们为此找到的所有解决方案放在一起,所以它都在一个地方。

其中一个答案 linked this post,非常有用.

除此之外我们还做了以下事情:

  • 选中所有项目属性上的“优化代码”框。不确定这是否会具体缩短启动时间,但它似乎对整体性能有所帮助。
  • 添加 AOT 和 LLVM。我们找到了一种方法来执行此操作,即使该选项在我们的 IDE 上不可用。这会大大增加构建时间,所以如果你想这样做,我建议只对发布版本这样做。
  • 启用Xamarin 快速渲染。这是一个实验性的东西,所以你应该阅读一些关于它的文档,但它是通过在 MainActivity.OnCreate() 方法上添加这一行 global::Xamarin.Forms.Forms.SetFlags("FastRenderers_Experimental");,在 global::Xamarin.Forms.Forms.Init(this, bundle);
  • 之前完成的
  • 更新我们的 Xamarin.Forms Nuget 版本。这需要在您的解决方案的所有项目上使用相同的版本,我们在点击手势方面遇到了一些问题,这些问题也因此得到了改善。
  • Link SDK 程序集。在 Linking 下的属性 > Android 选项中,您可以设置为 link "SDK Assemblies Only"。您也可以设置为所有程序集,但如果您使用的是自定义程序集,则不建议这样做。
  • 预加载屏幕。这大大提高了应用程序本身的性能,我们所做的是在每个屏幕、背景、下一个需要的地方加载视图和视图模型,因此当将它们推送到导航堆栈时,它们已经加载。这大大减少了页面之间的转换时间。

我找到了解决方案。例如,我们有 5 个选项卡。我们有 5 个视图模型或 5 个代码隐藏。我们定义了启动计时器方法的每个选项卡视图模型构造函数。第一个选项卡构造函数在计时器启动后 700 毫秒初始化。第二个选项卡在 1 秒后开始。让我们为此编写代码:

第一个选项卡主页和主页视图模型是 HomeViewModel。

public void HomeTimer()
{
    timer.Interval = 700;

    timer.Elapsed += (sender, e) => OnTimedEvent(sender, e);

    timer.AutoReset = false;

    timer.Enabled = true;
}

private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
    timer.Enabled = false;

    Yap(); // yap command all the page listview and get api.
}
System.Timers.Timer timer = new System.Timers.Timer();

public HomeViewModel()
{
    HomeTimer(); // hometimer starting
}

第二个选项卡是 MyPage,viewmodel 是 MyPageViewModel,构造函数是相同的:

public void MyPageTimer()
{
    timer.Interval = 1000; //look. home page starting 0.7 seconds after and mypage starting 1 seconds after.

    timer.Elapsed += (sender, e) => OnTimedEvent(sender, e);

    timer.AutoReset = false;

    timer.Enabled = true;
}

private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
    timer.Enabled = false;

    GetMypage(); // and getmypage method all the initialize the page and listview and webapi works.
}
System.Timers.Timer timer = new System.Timers.Timer();

public MyPageViewModel()
{
    MyPageTimer();
}

并且这个操作我从启动时删除了 1 秒。在此操作之前,我的应用程序开始 3.2 秒,现在开始 2.2 秒。