由2.4s优化到1s以内:Android App启动优化深度实践
Posted 好好说话行吗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了由2.4s优化到1s以内:Android App启动优化深度实践相关的知识,希望对你有一定的参考价值。
优化性能一直是我们程序员的追求。
在这个网络都追求5G了的时代,“卡”这个体验显然成为了一个极拉低印象分的问题,所以像阿里,还有腾讯、字节跳动、爱奇艺等,都非常重视这个问题,在面试中,如果这个方向表现优异,将会很值钱。
本次要和大家分享的就是“性能优化”这个技术,希望对大家的学习和工作有所帮助。
原文地址:https://blog.csdn.net/weixin_49559515/article/details/114885675
背景
我们的APP新版本,从2017年4月份提交第一行代码开始,就现在已经有4年的时间,在这4年多的时间里,APP的内容内容不断丰富,例如先后加入了求职招聘、问答、个人中心、二手机,小视频等等模块。同时对于以前的旧功能也在不断地完善,例如,丰富了发帖的内容、小视频详情页像抖音一样方便快捷、标签的聚合更加精准的吸引用户。
在功能、内容丰富的同时,不免会引入很多第三方的工具,例如友盟、个推、神策、腾讯云的视频组件、IM及时通讯组件,GreenDao数据库等等
随着代码量越来越多,第三方工具越来多的导致APP,首次启动的时候,时间较长,用户体验较差。
Nimbledroid统计Google Play各类别APP冷启动平均耗时 (Nexus 5 + Android 4.4)
[图片上传失败…(image-c82b9a-1565334335822)]
而Google Play排名前100的非游戏类的应用的冷启动时间统计为
39个冷启动时间在2秒以内
73个冷启动时间在3秒以内
而我们APP的冷启动时间为:
执行命令行
adb shell am start -W -n 包名/包名.activity.MainEntryActivity
ThisTime:最后一个启动的Activity的启动耗时;
TotalTime:自己的所有Activity的启动耗时;
WaitTime: ActivityManagerService启动App的Activity时的总时间(包括当前Activity的onPause()和自己Activity的启动)。
也就是说,在启动的时候,需要2.4s。
可见,还有很大的优化空间。
接下来,就通过本篇内容,深入的剖析一下,启动慢的原因,并给出合理的解决方案。
启动过程分析
开始,优化启动的过程,那么就要先了解一下,android系统,在启动一个APP的过程是什么样的?都做了什么事儿?
冷启动、热启动
冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用。
热启动:当启动应用时,后台存在该应用的进程(back键,home键,应用退出,但是没有销毁),从已有的进程中启动。
因为热启动是后台进程已经存在了,所以启动速度比较快,这里提到的优化是指冷启动。
Android冷启动过程相对比较复杂,需要经历35步,简单来说,需要5个过程
整个应用程序的启动过程要执行很多步骤,但是整体来看,主要分为以下五个阶段:
一. Step1 - Step 11:
Launcher通过Binder进程间通信机制通知ActivityManagerService,
它要启动一个Activity;
二. Step 12 - Step 16:
ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;
三. Step 17 - Step 24:
Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,
于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,
即将要启动的Activity就是在这个ActivityThread实例中运行;
四. Step 25 - Step 27:
ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,
以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;
五. Step 28 - Step 35:
ActivityManagerService通过Binder进程间通信机制通知ActivityThread,
现在一切准备就绪,它可以真正执行Activity的启动操作了。
在更加简单一点,从用户点击桌面图标开始,大致会经历以下几个过程:
在这个启动过程当中,可能会存在的几个问题:
1.点击图标很久都不响应。
2.首页显示太慢。
3.首页显示后无法操作。
而接下来,重点解决的问题就是,点击图标很久都不响应的问题。
优化工具
当,遇到一个问题的时候,到最后解决的步骤,无外乎有以下几个步骤。
Hugo是 jake Wharton大神制作的工具,可以在log当中打印每个方法的执行时间,可以帮我们定位到运行时间比较长的方法和函数,配置也相对简单。
接下来,就在代码当中实践一下。
本想观察一下 Application当中,初始化的时间
@DebugLog
@Override
public void onCreate()
super.onCreate();
initHttpClient();
// //初始化配置
initGlobal();
// CrashCaptureHandler.getInstance().initCrashHandler();
initJPush();
initGetTuiPush();
initSource();
initSmallVideoRecord();
initIM();
if (BuildConfig.DEBUG)
boolean hostUrlEnable = new HostUrlUtils().initHost(URLConstants.class.getDeclaredFields(), URLConstants.RELEASE_SERVER);
if (hostUrlEnable)
Dispatcher.hostUrlClass = URLConstants.class;
else
//正式环境才开始crash防护
install();
initAliyunLog();
initHuoDongHeZi();
initSensor();
initUmeng();
initLinkMe();
initRN();
观察打印的Log
2019-08-10 16:10:09.752 30634-30634/> V/MyApplication: ⇢ onCreate()
2019-08-10 16:10:09.941 30678-30678/? V/MyApplication: ⇢ onCreate()
2019-08-10 16:10:10.004 30692-30692/? V/MyApplication: ⇢ onCreate()
2019-08-10 16:10:10.124 30737-30737/? V/MyApplication: ⇢ onCreate()
2019-08-10 16:10:10.529 30678-30678/? V/MyApplication: ⇠ onCreate [587ms]
2019-08-10 16:10:10.569 30634-30634/? V/MyApplication: ⇠ onCreate [816ms]
2019-08-10 16:10:10.832 30737-30737/? V/MyApplication: ⇠ onCreate [707ms]
2019-08-10 16:10:10.881 30692-30692/? V/MyApplication: ⇠ onCreate [877ms]
2019-08-10 16:10:13.917 31109-31109/?:xg_service_v3 V/MyApplication: ⇢ onCreate()
2019-08-10 16:10:14.441 31109-31109/?:xg_service_v3 V/MyApplication: ⇠ onCreate [524ms]
可以发现,原来初始化onCreat被多次调用!
正常情况下,一个应用会开启一个进程,那么application会被执行一次,说明在启动的过程当中,不仅如此,因为初始化的重复调用,导致初始化的时间就有 2391ms!这就极大的影响到APP的启动速度!给用于一种,点击完图标没有反应的感觉。
解决问题
既然,问题已经发现了,就要解决这些问题。
既然发现是进程的问题,那么就要看看,在启动的过程当中,总共有哪些进程。
2019-08-10 16:40:07.881 3166-3166/? D/yzc: ?
2019-08-10 16:40:07.978 3225-3225/? D/yzc: ?:pushcore
2019-08-10 16:40:08.128 3298-3298/? D/yzc: ?:ipc
2019-08-10 16:40:08.172 3245-3245/? D/yzc: ?:pushservice
2019-08-10 16:40:11.754 3739-3739/?s:xg_service_v3 D/yzc: ?s:xg_service_v3
从中,可以看到除了APP的进程之外,还有 信鸽推送的进程,ipc进程,个推进程,极光的进程。
之前可能某些业务需要,集成了三家的推送,而每个推送都会在后台默默的开启一个进程来接收推送消息。自然就会导致APP的第一次初始化启动很慢。
和运营小伙伴确认,当前只有信鸽推送在使用,个推,极光就给去掉。那么去掉之后,再看一下启动时间。
同时也避免了多次初始化的问题!
相比之前的2391ms 优化了800ms! 接下来,继续优化,看看哪里还有可以优化的空间。
继续优化
Application初始化优化
在Application当中,可以看到,初始化的内容有
initGlobal();
初始化配置
initIM();
初始化及时通讯
initSource();
初始化APP相关版本配置
initSmallVideoRecord();
初始化短视频
install();
初始化放在Crash
initAliyunLog();
初始化阿里云相关内容
initHuoDongHeZi();
初始化活动盒子
initSensor();
初始化神策
initUmeng();
初始化友盟
initLinkMe();
初始化深度连接
initRN();
初始化ReactNative
分别统计一下每个初始化需要的的时间。
initBbsGlobal [73ms]
initIM [95ms]
initSource [0ms]
initSmallVideoRecord [11ms]
install [0ms]
initAliyunLog [19ms]
initHuoDongHeZi [69ms]
initSensor [191ms]
initUmeng [14ms]
initLinkMe [63ms]
initRN [0ms]
根据统计,可以看到耗时较长的方法有神策、IM聊天、活动盒子、深度连接、配置文件。
对于这些时间长的,在不影响功能的情况下,可以尝试放在子线程当中进行初始化,不占用主线程的资源。
new Thread(new Runnable()
@Override
public void run()
initIM();
initSource();
initSmallVideoRecord();
initLinkMe();
initUmeng();
if (!URLConstants.RELEASE_SERVER)
boolean hostUrlEnable = new HostUrlUtils().initHost(URLConstants.class.getDeclaredFields(), URLConstants.RELEASE_SERVER);
if (!hostUrlEnable)
new AlertDialog.Builder(getApplicationContext())
.setTitle("未检测到可用的URL")
.setMessage("请确诊URL地址可用")
.setPositiveButton("退出", null).show();
Dispatcher.hostUrlClass = URLConstants.class;
else
//正式环境才开始crash防护
install();
initAliyunLog();
initHuoDongHeZi();
).start();
经过改造,看一下启动时间。
相比之前又优化了 300ms!,相比没有优化之前优化了1132ms! 也就是快了 1秒 多的时间,可以说效果还是十分明显的。
同时可以看到,Application的初始化时间当前仅需199ms
MainEntryActivity初始化优化
在 Application的优化告一段落,关注一下 MainEntryActivity 这个 Activity 是进入app的一个Activity,在这个 Activity的onCreate()当中 进行了一些请求操作,看看这里面有什么可以优化的地方。
在这个里,有两个操作造成耗时时间比较长,一个是
isCityInviteNetWork()
这个方法是当用户登录的时候,根据用户获取到用户的地理位置信息并存储。
这个方法完全可以放在子线程当中,不占用主线程的资源。
checkAdversiterment()
这个是在网络获取开屏广告的方法,这个需要请求接口,获取到开屏广告并展示的方法。
对于这个方法,也可以子线程当中异步操作,第一次请求下来缓存起来,从第二次进入APP,在进行展示,这样避免了主线程的耗时操作。
经过这些操作之后,可以看到启动时间,已经优化到了1s左右。
感想
虽然,没有目前没有达到秒开的效果,但是比起优化之前已经有了很大的区别,优化效果。今后,还会继续优化,争取达到一个更好的效果。
之前我看有朋友说可以设置主题达到秒开的效果,我试了一下好像不太行,也需要大概500ms左右,如果大家有好的想法和建议,欢迎给我留言!我们一起讨论!
性能优化总结
性能优化这个点的知识要想讲明白篇幅会比较长,鉴于篇幅原因,我这里直接把详解部分整理成了一份PDF。
这份《超全App性能优化知识技能手册》一共有721页,4个大点,25个小章节,不仅仅有详细的底层原理的解析,还有专门的实践案例
有需要的朋友,直接戳此处蓝色字体,进入我们两千人的技术交流圈,共享文件夹自取。
(另外还有一个系列配套的性能优化专题的讲解视频需要的可以一起打包)
第一章 设计思想与代码质量优化
- 六大原则(单一职责原则、里氏替换原则、依赖倒转原则、接口隔离原则……)
- 设计模式:结构型模式(桥接模式、适配器模式、装饰器模式、代理模式、门面(外观)模式……),创建型模式(建造者模式、单例模式、抽象工厂模式、工厂方法模式……)
- 数据结构(数组、栈、队列、链表、树……)
- 算法(排序算法、查找算法……)
第二章 程序性能优化
- 启动速度与执行效率优化(冷启动和热启动解析、APP 启动黑白屏解决办法、APP 卡顿问题分析及解决方案、启动速度与执行效率优化之 StrictMode……)
- 布局检测与优化(布局层级优化、过度渲染……)
- 内存优化(内存抖动和内存泄漏、内存大户,Bitmap 内存优化、Profile 内存监测工具、Mat 大对象与泄漏检测、耗电优化、网络传输与数据存储优化网络传输与数据存储优化、APK 大小优化、屏幕适配……)
- 耗电优化(Doze&Standby、Battery Historian、JobScheduler、WorkManager、)
- 网络传输与数据存储优化(google 序列化工具 protobuf、7z 极限压缩……)
- APK 大小优化(APK 瘦身、微信资源混淆原理……)
- 屏幕适配(进行适配的原理、屏幕分辨率限定符与 smallestWidth 限定符适配原理、为什么选择 smallestWidth 限定符适配、怎么适配其他 module、常见问题处理……)
- OOM 问题原理解析(adj 内存管理机制、JVM 内存回收机制与 GC 算法解析、生命周期相关问题总结、Bitmap 压缩方案总结……)
- ANR 问题解析(AMS 系统时间调节原理、程序等待原理分析、ANR 问题解决方案……)
- Crash 监控方案(Java 层监控方案、Nativie 层监控方案……)
第三章 开发效率优化
- 分布式版本控制系统 Git(企业高效持续集成平台场景介绍、GIT 分布式版本控制系统、GIT 分支管理……)
- 自动化构建系统 Gradle:
Gradle 与 Android 插件(gradle 与 android gradle 插件的关系、Gradle Transform API 的基本使用……),
Gradle Transform API 的基本使用(什么是 Transform、Transform 的使用场景、Transform API 学习、输入的类型……)
自定义插件开发(Gradle 插件简介、开始准备、实践、自定义 Gradle 插件、buildSrc 模块方式……)
插件实战(多渠道打包、发版自动钉钉……)
第四章 APP 性能优化实践
- 启动速度(应用启动的一般流程、冷启动和热启动、启动速度的测量、启动窗口优化、线程优化、系统调度优化、GC 优化、IO 优化、资源重排、主页布局优化、类加载优化、选择合适的启动框架、减少 Activity 的跳转层次、厂商优化、后台保活……)
- 流畅度(性能问题分析的一些工具和套路、通过性能数据数据分析、Android 平台性能导致的性能案例、Android App 自身导致的性能问题、低内存的数据特征和行为特征、应用宝、讯飞输入法无障碍服务导致的整机卡顿分析、字节跳动:今日头条图文详情页秒开实践……)
- 抖音在 APK 包大小资源优化的实践(图片压缩、webp 无侵入式兼容、多 DPI 优化、重复资源合并、shrinkResource 严格模式、资源混淆(兼容 aab 模式)、ARSC 瘦身……)
- 优酷响应式布局技术全解析(优酷APP响应式布局技术概述、优酷APP响应式布局Android落地、在分发场景的落地、在消费场景的落地、优酷APP响应式布局之测试方案……)
- 网络优化(手机淘宝在网络的链路优化、百度 APP 在网络深度优化的实践……)
- 手机淘宝双十一性能优化项目揭秘(一秒法则的实现、启动时间和页面帧率提升 20%、Android 手机内存节省50%……)
- 高德 APP 全链路源码依赖分析(高德 APP 平台架构、基础实现原理、项目架构、应用场景及实现原理……)
- 彻底干掉OOM的实战经验分享(排查内存泄漏、兜底策略、内存峰值太高、特大图排查优化……)
- 微信 Android终端内存优化实践(Activity 泄露检测、Bitmap 分配及回收追踪、Native 内存泄漏检测、线程监控、内存监控……)
总结
如果你也想提升自己移动开发的性能优化技术,或者是正在准备移动开发岗的面试,我觉得这份笔记你必定不能错过。
有需要的朋友,直接戳此处蓝色字体,进入我们两千人的技术交流圈,共享文件夹自取。
以上是关于由2.4s优化到1s以内:Android App启动优化深度实践的主要内容,如果未能解决你的问题,请参考以下文章