一、App启动分类

1.冷启动 Cold start

在启动应用前,系统还没有App的任何进程。比如设备开机后应用的第一次启动,系统杀掉应用进程 (如:系统内存吃紧引发的 kill 和 用户主动产生的 kill) 后 的再次启动等。那么自然这种方式下,应用的启动时间最长。

2.热启动 Warm start
当应用中的 Activities 被销毁,但在内存中常驻时,应用的启动方式就会变为暖启动。相比冷启动,暖启动过程减少了对象初始化、UI的布局和渲染。启动时间更短。但启动时,系统依然会展示一个空白背景,直到第一个 Activity 的内容呈现为止。

3.温启动 Lukewarm start
用户退出您的应用,但随后重新启动。该过程可能已继续运行,但应用程序必须通过调用onCreate()从头开始重新创建活动。系统从内存中驱逐您的应用程序,然后用户重新启动它。进程和Activity需要重新启动,但任务可以从保存的实例状态包传递到onCreate()中。

启动速度优化主要是针对冷启动方式。下面看下冷启动的时候会做哪些工作。

#二、冷启动
应用发生冷启动时,系统有三件任务要做:

  • 加载启动App;
  • App启动之后立即展示出一个空白的Window;
  • 创建App的进程;

创建App进程后,会马上执行以下任务:

  • 初始化应用中的对象 (比如 Application 中的工作);
  • 启动主线程 (UI 线程) ;
  • 创建第一个 Activity;
  • 加载内容视图 (Inflating) ;
  • 计算视图在屏幕上的位置排版 (Laying out);
  • 进行第一次绘制 (draw)。

只有当应用完成第一次绘制,系统当前展示的空白背景才会消失,才会被 Activity 的内容视图替换掉。也就是这个时候,用户才能和我们的应用开始交互。下图展示了冷启动过程系统和应用的一个工作时间流:

三、优化思路

作为普通应用,App进程的创建等环节我们是无法主动控制的。开发人员唯一能做的就是**在Application 和 第一个 Activity 中,减少 onCreate() 方法的工作量,从而缩短冷启动的时间。**像应用中嵌入的一些第三方 SDK,都建议在 Application 中做一些初始化工作,开发人员不妨采取懒加载的形式移除这部分代码,而在真正需要用到第三方 SDK 时再进行初始化。

Google也给出了启动加速的方向:

1、利用提前展示出来的Window,快速展示出来一个界面,给用户快速反馈的体验;
2、 避免在启动时做密集沉重的初始化(Heavy app initialization);
3、 定位问题:避免I/O操作、反序列化、网络操作、布局嵌套等

四、正确测量评估启动性能的方法

1.display time

从Android KitKat版本开始,Logcat中会输出从程序启动到某个Activity显示到画面上所花费的时间。这个方法比较适合测量程序的启动时间。

2.reportFullyDrawn

我们通常来说会使用异步懒加载的方式来提升程序画面的显示速度,这通常会导致的一个问题是,程序画面已经显示,可是内容却还在加载中。为了衡量这些异步加载资源所耗费的时间,我们可以在异步加载完毕之后调用activity.reportFullyDrawn()方法来告诉系统此时的状态,以便获取整个加载的耗时。

3.Traceview

告诉我们每一个方法执行了多长时间.这个工具可以通过 Android Device Monitor 或者从代码中启动。

3.1 Android Device Monitor启动

启动应用,点击 Start Method Tracing,应用启动后再次点击,会自动打开刚才操作所记录下的.trace文件,建议使用DDMS来查看,功能更加方便全面。

3.2 代码启动

①在onCreate开始和结尾打上trace

    Debug.startMethodTracing("GithubApp");...Debug.stopMethodTracing();

注意加读写权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

运行程序, 会在sdcard上生成一个"GithubApp.trace"的文件.

②通过adb pull将文件导出到本地

adb pull /sdcard/GithubApp.trace ~/temp

③打开DDMS分析trace文件
④分析trace文件

  • 在下方的方法区点击"Real Time/Call", 按照方法每次调用耗时降序排.
  • 耗时超过500ms都是值得注意的.
  • 看左边的方法名, 可以看到耗时大户就是我们用的几大平台的初始化方法, 特别是Bugly, 还加载native的lib, 用ZipFile操作-等.
  • 点击每个方法, 可以看到其父方法(调用它的)和它的所有子方法(它调用的).
  • 点击方法时, 上方的该方法执行时间轴会闪动, 可以看该方法的执行线程及相对时长.

4.Systrace

在onCreate方法里面添加trace.beginSection()与trace.endSection()方法来声明需要跟踪的起止位置,系统会帮忙统计中间经历过的函数调用耗时,并输出报表。

5.adb命令计算 App 的启动时间

adb shell am start -W packageName/packageName.activity

例如:

adb shell am start -W com.media.painter/com.media.painter.PainterMainActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.media.painter/.PainterMainActivity }
Status: ok
Activity: com.media.painter/.PainterMainActivity
ThisTime: 355
TotalTime: 355
WaitTime: 365
Complete

(注意 Android 5.0 之前的手机是没有 WaitTime 这个值的)

  • WaitTime 就是总的耗时,包括前一个应用 Activity pause 的时间和新应用启动的时间;
  • ThisTime 表示一连串启动 Activity 的最后一个 Activity 的启动耗时;
  • TotalTime 表示新应用启动的耗时,包括新进程的启动和 Activity 的启动,但不包括前一个应用 Activity pause 的耗时。
  • 开发者一般只要关心 TotalTime 即可,这个时间才是自己应用真正启动的耗时。

五、优化方案

1.主题切换

通过主题设置,不显示启动时的白屏背景。有以下几种方案:

1.1 直接不显示白屏,直到程序初始化完毕直接显示第一个Activity

<style name="LaunchStyle" parent="Theme.AppCompat.Light.DarkActionBar">......<item name="android:windowIsTranslucent">true</item><item name="android:windowNoTitle">true</item>
</style>

或者

    <style name="LaunchStyle" parent="Theme.AppCompat.Light.DarkActionBar">......<item name="android:windowDisablePreview">true</item></style>

然后设置给第一个activity

 <activity android:name=".MainActivity"android:theme="@style/LaunchStyle"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>

如果将主题设置到Application,那所有的Activity的主题都会改变

然后在MainActivity中在加载布局之前,重新设置主题

 @Overrideprotected void onCreate(Bundle savedInstanceState) {setTheme(R.style.AppTheme);super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}

这样相当于把白屏变成透明的,隐藏起来了,但是会有一种点击图标后卡住了,过了好几秒才进入App的感觉。这种方案用户体验很差。

1.2把白屏当成闪屏页用

可以通过主题中的 windowBackground 属性,自定义应用启动时的窗口背景。窗口背景显示的内容,Google推荐两种方案,一种是显示Logo,一种利用了 placeholder ,与主界面的 UI 框架保持一致,给用户产生一种应用启动非常快的视觉感受。

①显示Logo使用方式:

drawable/branded_launch_screens:

 <?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android"android:opacity="opaque"><!--黑色背景颜色--><item android:drawable="@android:color/black" /><!-- 产品logo--><item><bitmapandroid:gravity="center"android:src="@mipmap/empty_image01" /></item><!-- 右上角的图标元素 --><item><bitmapandroid:gravity="top|right"android:src="@mipmap/github" /></item><!--最下面的文字--><item android:bottom="50dp"><bitmapandroid:gravity="bottom"android:src="@mipmap/ic_launcher" /></item></layer-list>

android:opacity=”opaque”参数是为了防止在启动的时候出现背景的闪烁。

定义style:

    <style name="AppTheme.Launcher"><item name="android:windowBackground">@drawable/branded_launch_screens</item></style>

或者直接使用一张图片

 <style name="AppTheme.Launcher"><item name="android:windowFullscreen">true</item><item name="android:windowBackground">@mipmap/app_welcome</item></style>

然后将这个主题设置给启动的 Activity。

②使用placeholder:

模拟了一个高度为25dp的状态栏和一个高度为56dp的标题栏。
drawable/placeholder_ui

 <?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android"android:opacity="opaque"><!--状态栏颜色--><item android:drawable="@color/colorPrimaryDark" /><!--假装这里是个toolbar--><itemandroid:drawable="@color/colorPrimary"android:top="25dp" /><!--状态栏25+toolbar56=距离top81--><itemandroid:drawable="@android:color/white"android:top="81dp" /></layer-list>

定义style:

 <style name="AppTheme.Launcher"><item name="android:windowBackground">@drawable/placeholder_ui</item></style>

然后将这个主题设置给启动的 Activity。

③还可以适度结合 Activity 内容视图使用动画过渡效果。

2.避免Application的onCreate进行太多的工作

在Application初始化的地方做太多繁重的事情是可能导致严重启动性能问题的元凶之一。Application里面的初始化操作不结束,其他任意的程序操作都无法进行。Application的onCreate中会做大量第三方组件的初始化工作,其实很多组件是需要做区别对待的,有些可以做延迟加载,有些可以放到其他的地方做初始化操作,特别需要留意包含Disk IO操作,网络访问等严重耗时的任务,他们会严重阻塞程序的启动。

注意点:

  • 项目是多进程架构,只在主进程执行Application的onCreate();
  • 流程梳理,延后执行;
  • 异步加载、延时加载、懒加载

示例如下,Application以及首屏Activity中我们主要做了:

如何判断第三方的库是不是能放在子线程里面:

需要初始化的第三方一般分为两种, 一种是第三方平台的SDK(推送, 分享, 反馈, 统计等) 这个可以通过看其SDK文档, 结合业务需求考虑. 例如分享, 反馈一般不是必须要应用一开启就能用的, 这类业务一般层级比较深, 有足够的理由让它们在后台异步初始化. 另外一种第三方是第三方的库, 一般来说, 建议阅读其源码, 了解其实现原理, 再决定是否放在后台初始化.

项目修改:

将友盟、Bugly、听云、GrowingIO、BlockCanary等组件放在WorkThread中初始化;

延迟地图定位、ImageLoader、自有统计等组件的初始化:地图及自有统计延迟4秒,此时应用已经打开;而ImageLoader因为调用关系不能异步以及过久延迟,初始化从Application延迟到SplashActivity;而EventBus因为再Activity中使用所以必须在Application中初始化。

3.避免首个Activity的onCreate进行太多的工作

使用延迟加载。确保在Activity的页面显示出来之后再进行加载数据,避免过早或过晚的加载导致页面空白时间过长。可采用以下 代码实现延迟加载。在Activity的onCreate方法中:

getWindow().getDecorView().post(new Runnable() {@Overridepublic void run() {myHandler.post(mLoadingRunnable);}
});

4.MultiDex初次启动优化

4.1问题

随着代码数量的膨胀,工程本身的代码加上引用的第三方库的代码中方法数量会超过65536的限制。是由于DEX文件格式限制,一个DEX文件中method个数采用使用原生类型short来索引文件中的方法,也就是4个字节共计最多表达65536个method,field/class的个数也均有此限制。 Google为构建超过65K方法数的应用提供官方支持的方案:MultiDex。

但是在Dalvik下MultiDex有个问题:5.0以下某些低端机会出现ANR或者长时间卡顿不进入引导页,而罪魁祸首是MultiDex.install(Context context)的dexopt过程耗时过长。因此需要在初次启动时做特别处理。

而5.0以上会使用ART,在ART下MultiDex是不存在这个问题的,这主要是因为ART下采用Ahead-of-time (AOT) compilation技术,系统在APK的安装过程中会使用自带的dex2oat工具对APK中可用的DEX文件进行编译并生成一个可在本地机器上运行的文件,这样能提高应用的启动速度,只是在安装过程中进行了处理这样会影响应用的安装速度。

4.2解决思路

1、在Application.attachBaseContext(Context base)中,判断是否初次启动,以及系统版本是否小于5.0,如果是,跳到2;否则,直接执行MultiDex.install(Context context)。

2、开启一个新进程,在这个进程中执行MultiDex.install(Context context)。执行完毕,唤醒主进程,自身结束。主进程在开启新进程后,自身是挂起的,直到被唤醒。

3、唤醒的主进程继续执行初始化操作。

最后

如果你看到了这里,觉得文章写得不错就点个赞呗?转发分享关注一下我,以后还会更新技术干货,谢谢您的支持!如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。

有一句老话说的好:
“比你优秀的对手在学习,你的仇人在磨刀,你的闺蜜在减肥,隔壁老王在练腰,我们必须不断学习,否则我们将被学习者超越。”
当然一个人学习是枯燥的,还需要一个良好的学习氛围,因此我组建了一个学习交流探讨的社群,欢迎大家一起来交流探讨共同进步。还有一些收集整理的资料,感兴趣的可以来一起学习,共同进步!

针对Android开发的同行,这边给大家整理了一些资料,其中分享内容包括但不限于
【高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术】
希望能帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也是可以分享给身边好友一起学习的!

转发+点赞,加入Android开发交流群(820198451)获取小编为大家收录的进阶资料和面试题库



转发+点赞,加入Android开发交流群(820198451)获取小编为大家收录的进阶资料和面试题库

Android架构师之路很漫长,一起共勉吧!

性能优化:Android App启动速度优化相关推荐

  1. App 启动速度优化

    前言​​​​​​​ APP打开的一瞬间速度快慢:就好比人的第一印象,快速的打开一个应用往往给人很舒服的体验.app经常性卡顿启动速度很慢,这无疑是对用户的流失. 启动方式介绍 APP启动的方式分为3种 ...

  2. Android 应用性能优化(2)---优化Android 应用启动速度

    优化Android 应用启动速度(应用启动慢的真正原因探究) 开门见山告诉答案: 一个Android 应用真正启动慢的原因是在Application 里面做了耗时的操作.把这些耗时的操作找出来并且ne ...

  3. 优化Android App性能?十大技巧

    优化Android App性能?十大技巧 android shangxuetang 1年前 (2014-05-27) 3399℃ 4评论 android 无论锤子还是茄子手机的不断冒出,Android ...

  4. App性能优化(布局优化,线程优化,app瘦身优化,页面切换优化,App启动优化,内存优化)

    Android APP性能优化(最新总结) 在目前Android开发中,UI布局可以说是每个App使用频率很高的,随着UI越来越多,布局的重复性.复杂度也随之增长,这样使得UI布局的优化,显得至关重要 ...

  5. 爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结

    本文由爱奇艺技术团队原创分享,原题<爱奇艺Android客户端启动优化与分析>. 1.引言 互联网领域里有个八秒定律,如果网页打开时间超过8秒,便会有超过70%的用户放弃等待,对Andro ...

  6. Android 系统(102)---Android APP耗电优化

    Android APP耗电优化 可能造成耗电的一些原因 网络请求耗电,而且手机数据网络进行http请求比无线网进行http请求更加耗电,因为数据网络调用到一些底层的硬件模块,就如GPS一样,当手机打开 ...

  7. Android性能调优:App启动速度优化

    一.App启动分类 1.冷启动 Cold start 在启动应用前,系统还没有App的任何进程.比如设备开机后应用的第一次启动,系统杀掉应用进程 (如:系统内存吃紧引发的 kill 和 用户主动产生的 ...

  8. Android面试-Android性能优化和内存优化、APP启动速度一线大厂的实战案例解析

    一.Android 内存管理机制 二.优化内存的意义 三.避免内存泄漏 四.优化内存空间 五.图片管理模块的设计与实现 六.总结 深入探索Android内存优化 第一章.重识内存优化 第二章.常见工具 ...

  9. 十大技巧优化Android App性能

    无论锤子还是茄子手机的不断冒出,Android系统的手机市场占有率目前来说还是最大的,因此基于Android开发的App数量也是很庞大的.那么,如何能开发出更高性能的Android App?相信是软件 ...

最新文章

  1. <笔记2>numpy的生成随机数用法小记
  2. linux svn可视化,Ubuntu 14.04如何安装可视化SVN
  3. PHP 找出数值数组中不重复最大的10个数和最小的10个数
  4. 外部链接linux下的mysql,Linux下mysql实现远程链接
  5. POST教程笔记 - WinHttp获取网页源码
  6. Linux DMA 内存拷贝与memcpy 速率比较
  7. 高校计算机基础能力测试文字处理,高校计算机基础论文3篇(共8238字).doc
  8. 有线电视的现状与发展,全国一网与广电5G一体化建设
  9. 可视化 nlp_使用nlp可视化尤利西斯
  10. 获取select被选中的option的值
  11. java - 人员分配组合
  12. [转]Spinner的常用技巧
  13. 显卡显存故障检测工具_为RTX30系显卡做准备,骨伽GEX750金牌全模组电源装机体验...
  14. zip和rar文件的contentType
  15. @property基本概念
  16. 计算机科学与工程版面费,《计算机工程与设计》版面费问题 - 论文投稿 - 小木虫 - 学术 科研 互动社区...
  17. kubectl 命令详解(三十五):rollout undo
  18. PHP单元测试框架 - PHPUnit介绍
  19. 工厂生产管理流程有哪些环节?
  20. Vim-Plug 下载安装

热门文章

  1. Chaos Mesh Test(在k8s对mysql,redis zookeeper 进行chaos 测试)
  2. 浏览器插件之ActiveX开发
  3. 【托业】【怪兽】TEST02
  4. android AlarmManager实现定时器
  5. 今天终于解决了U盘0字节问题
  6. 单片机实验——0到60秒的计时器
  7. 外媒称字节跳动将开发智能手机 官方不予置评
  8. 量化投资入门指南:量化交易系统框架与阿尔法模型
  9. Redis 安装配置开机启动整合SpringBoot以及配置文件详解
  10. ADS和candence如何调用veriloga文件并进行编译?