联系我们: 有道技术团队助手:ydtech01 / 邮箱:ydtech@rd.netease.com

本文的重点在于如何定量的排查冷启动过程中的耗时操作,并提供对应的优化思路和实践方法总结。同时文本涉及到的冷启动优化主要涵盖两个方面:Application 的性能优化和 Launcher Activity 的性能优化。

一、背景

中国大学 MOOC 是网易与高教社携手推出的在线教育平台,目前,经过长期的产品打磨和钻研,在课程数量、质量以及影响力,中国大学 MOOC 已成为全球领先的中文慕课平台。同时经过此次优化,冷启动速度整体提升27%。

在我们日常开发中,随着 app 整体迭代次数增多,由于长久以来的迭代需求,android app 本身也集成了较多的第三方组件和 SDK,同时在日常迭代中,也是以业务迭代需求实现为主要目的,导致现在 app 本身,或多或少存在一些性能可优化空间。所以有必要进行性能优化,提升用户体验。

此次优化,主要侧重于两个方面:

  • Application 的性能优化
  • app 启动页性能优化

该文档重点不在于代码规范和业务代码逻辑导致的性能问题,而是在假设代码无明显、严重性能漏洞,并且不改变原有业务逻辑,量化性能监测数据和问题,并针对其进行优化修改。

二、冷启动速度优化

2.1 相关知识点

2.1.1 冷启动耗时统计

adb shell am start -S -W [packageName]/[activiytName]

上述 adb 命令中,几个关键参数说明:

  • -S:表示启动该 app 前先彻底关闭当前 app 进程
  • -W:启动并输出相关耗时数据
  • packageName:app 的 applicationID
  • activityName:app 启动需要拉起的 Activity,如果用于统计冷启动耗时,那么该参数即为应用的第一个启动的 Activity( intent-filter 为 LAUNCHER 的 Activity )

再执行上诉 adb 后,会成功唤起 APP,并在控制台输出三个比较关键的参数:

  • LaunchState:启动模式,上诉启动模式为冷启动
  • WaitTime:系统启动应用耗时= TotalTime +系统资源启动时间(单位 ms )
  • TotalTime:应用自身启动耗时=该 Activity 启动时间+应用 application 等资源启动时间(单位 ms )

对于应用层面得冷启动性能优化,我们关注的时间 TotalTime,该时间大致可以概括为:Application 构造方法→该 Activity 的 onWindowFocusChange 方法时间总和。而这个过程也可以粗略认知为,用户点击桌面图标到 app 第一个 Activity 获取焦点,业务代码执行的总时间(针对业务代码的优化,我们暂时不关心 Zygote 进程、Launcher 进程、AMS 进程的交互)。

2.1.2 冷启动耗时堆栈观察方法:

在 Android API>=26 的系统版本中,建议使用 CPU Profile 或者 Debug.startMethodTracing 进行监控并导出 trace 文件进行分析。不管哪种方式,采集堆栈信息都有两种模式:采样模式和追踪模式。追踪模式会一直抓取数据,对设备性能要求较高。

(1)CPU Profile

(2)Debug.startMethodTracing

由于冷启动涉及到业务应用层面的时间是:该 Activity 启动时间+应用 application 等资源启动时间,所以我们在 Application 构造方法中开始采集,在第一个 Activity 的 onWindowFocusChange 中停止采集,并输出 trace文件。

/*** 在Application构造方法中开始采集*/
public UcmoocApplication() {//保存Trace文件的目录File file = new File(Environment.getExternalStorageDirectory(), "ucmooc.trace");//采集方式有以下两种,根据需求选择其一//第一种:通过采样的方式,追踪堆栈信息if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//通过采样方式追踪堆栈信息,需要指定文件保存目录、文件最大大小(单位M)、采样间隔(单位us)Debug.startMethodTracingSampling(file.getAbsolutePath(), 8, 1000);}//第二种:通过追踪的方式,全量采集堆栈信息Debug.startMethodTracing(file.getAbsolutePath());coreApplication = new CoreApplication();
}
/*** 在启动后的第一个Activity的onWindowFocusChanged中停止监听** @param hasFocus*/
@Override
public void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);Debug.stopMethodTracing();
}

同时,由于该操作涉及到文件读写权限,需要手动授予 APP 该权限

2.1.3 .trace 日志文件阅读:

在导出获取到 .trace 文件后,把 .trace 拖动至 androidStudio 编辑区;或者直接浏览 CPU Profile 视图,便可对程序运行的堆栈进行分析:

上图就是 trace 文件打开后的效果,展示的是基于 CPU 使用和线程运行状况,针对启动速度的优化,需要关注的上图标注的几个点:

(1)CPU 运行时间轴:横向拖动可以选择查看的时间范围

(4)当前设备 CPU 轮转的线程:点击可以选择需要查看的线程,我们重点关注主线程

(2)当前选择线程,跟随时间轴,各个方法栈的调用情况和其耗时状况。其不同颜色分别代表

  • 黄色:android 系统方法(FrameWork 层代码,如果需要最终更底层的方法,需要最终 C/C++ 方法调用栈)
  • 蓝色:Java JDK 方法
  • 绿色:属于当前 app 进程执行的方法,包括一些类加载器和我们的业务代码(启动速度优化主要针对这一部分)

(3)各个方法栈的调用顺序和耗时情况,可以选择不用的排序方式和视图。

所以一般排查耗时方法时,建议先通过(2)视图直观检测到耗时较为严重的方法,锁定后,在(3)视图中查看具体的方法调用顺序。

2.2 优化步骤

由于在冷启动过程中,业务代码耗时主要集中在 Application 和 launcher Activity 中,所以优化过程也是分别针对这两块进行优化。

2.2.1 优化成果

使用 2.1.1 的方式,在优化前后,分别做了 10 次冷启动耗时统计,结果如下:

启动速度整体提升 27%。

2.2.2 Application 优化

通过 trace 文件,可以直观的发现,在 application 中,耗时最长的方法是其生命周期中的 onCreate 方法,其中在 onCreate 方法中,耗时比较长的方法有:initMudleFactory、initURS、Unicorn.init、initUmeng。

在 Top Down 视图中,可以更加直观的看出,此次采样,也正是这四个方法耗时最多。

通过源码排查,这是个方法,均是第三方 SDK 的初始化,同时在这几个 SDK 内部,都含有较多的 IO 操作,并且内部实现了线程管理以保证线程安全,所以可以将这几个 SDK 的初始化,放在子线程中完成。这里以友盟 SDK 为例:

/**
* 友盟SDK中有涉及到线程不安全的地方,都自己维护了线程,保证线程安全
**/
try {var6 = getClass("com.umeng.umzid.ZIDManager");if (var6 == null) {Log.e("UMConfigure", "--->>> SDK 初始化失败,请检查是否集成umeng-asms-1.2.x.aar库。<<<--- ");(new Thread() {public void run() {try {Looper.prepare();Toast.makeText(var5, "SDK 初始化失败,请检查是否集成umeng-asms-1.2.X.aar库。", 1).show();Looper.loop();} catch (Throwable var2) {}}}).start();return;}
} catch (Throwable var27) {}/**
* 在友盟SDK内部中有很多IO操作的地方,和加锁操作,所以可以将SDK初始化操作,放在子线程中
**/
if (!TextUtils.isEmpty(var1)) {sAppkey = var1;sChannel = var2;UMGlobalContext.getInstance(var3);k.a(var3);if (!needSendZcfgEnv(var3)) {FieldManager var4 = FieldManager.a();var4.a(var3);}synchronized(PreInitLock) {preInitComplete = true;}
}

最终,我们可以把上面提到的几个 SDK 初始化工作放入在子线程中:

private void initSDKAsyn(){new Thread(() -> {if (Util.inMainProcess()){// 登录initURS();if (BuildConfig.ENTERPRISE) {Unicorn.init(BaseApplication.this, "", QiyuOptionConfig.options(), new QiyuImageLoader());initModuleRegister();} else {Unicorn.init(BaseApplication.this, "", QiyuOptionConfig.options(), new QiyuImageLoader());}// 初始化下载服务try {initDownload();} catch (Exception e) {NTLog.f(TAG, e.toString());}}initModuleFactory();initUmeng();}).start();
}

对于一些必须在主线程中初始化完成的 SDK,可以考虑使用 IdleHandler,在主线程空闲时,完成初始化(关于 IdleHandler 会在下面讲到)。

2.2.3 Launcher Activity 优化

auncher Activity 是 WelcomeActivity,在对 Application 优化结束后,再对 WelcomeActivity 进行优化,还是和上路的思路一样,先通过 trace 文件追踪:

可以看到,在 WelcomeActivity 的 onCreate 方法中,耗时较多的三个地方,分别是:initActionBar、EventBus.register、setContentView,下面针对这三块内容,分别进行对应的优化操作:

(1)initActionBar

在上图中,可以看到,initActionBar 中最耗时的操作是 getSupportActionBar,通过研究代码发现,在WelcomeActivity中,并不需要操作 actionBar,所以直接复写父类方法,去掉 super 调用即可。

** (2)EventBus.register**

EventBus 注册时,性能较差,是因为在改过程中涉及到大量的反射操作,所以对性能损耗较大。通过查看官方文档,该问题在 EventBus3.0 中得到了很好的处理,主要是通过 apt 技术增加索引,提升效率。(当前项目未升级版本,待后期优化)

(3)setContentView

setContentView 是 Activity 渲染布局时的必要方法,其耗时的点在于,解析 xml 布局文件时,使用了反射,所以如果 xml 布局文件非常复查的时候,可以使用androidx.asynclayoutinflater:asynclayoutinflater进行异步加载 xml 文件,使用方式如下:

new AsyncLayoutInflater(this).inflate(R.layout.activity_welcome, null,(view, resid, parent) -> {setContentView(view);});

三、优化总体方法汇总

上面针对冷启动优化是基于当前项目本身做的步骤,这里汇总一些冷启动通用的优化思路

(1)合理的使用异步初始化、延迟初始化和懒加载机制:主要针对 Application 中各种 SDK 的初始化

(2)在主线程中应当避免很耗时的操作,比如 IO 操作、数据库读写操作

(3)简化 launcher Activity 的布局结构,如果非常复杂的布局,可以有以下两种方式进行优化:

  • 建议使用约束布局(ConstraintLayout)来减少布局嵌套避免过度渲染。
  • 使用 androidx.asynclayoutinflater:asynclayoutinflater 进行异步加载 xml 文件。

(4)合理使用 IdleHandler 进行延迟初始化,使用方式如下:

/*** 需要在当前线程中处理耗时任务,并且并不需要马上执行的话,可以使用IdleHandler* 这样该任务可以消息队列空闲时,被处理*/
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {@Overridepublic boolean queueIdle() {//此处添加处理任务//返回值为false:则执行完毕之后移除这条消息,//返回值为true:则则执行完毕之后依然保留,等到下次空闲时会再次执行,return false;}
});

(5)开始严苛模式(StrictMode)

该模式并不能帮我们自动优化性能,而是可以帮助我们检测出我们可能无意中或者一些第三方 SDK 中做的会阻塞 Main 线程的事情(比如磁盘操作、网络操作),并将它们提醒出来,以便在开发阶段进行修复。其检测策略有线程检测策略和虚拟机检测策略,我们可以设置需要检测的操作,当代码操作违规时,可以通过 Logcat 或者直接崩溃的形式提醒我们,具体使用方式如下

/*** 开启严苛模式,当代码有违规操作时,可以通过Logcat或崩溃的方式提醒我们*/
private void startStrictMode() {if (BuildConfig.DEBUG) { //一定要在Debug模式下使用,避免在生产环境中发生不必要的崩溃和日志输出//线程检测策略StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads()  //检测主线程磁盘读取操作.detectDiskWrites() //检测主线程磁盘写入操作.detectNetwork() //检测主线程网络请求操作.penaltyLog() //违规操作以log形式输出.build());//虚拟机检测策略StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects() //检测SqlLite泄漏.detectLeakedClosableObjects() //检测未关闭的closable对象泄漏.penaltyDeath() //发生违规操作时,直接崩溃.build());}
}

中国大学 MOOC Android 性能优化:冷启动优化总结相关推荐

  1. 毕博与中国大学mooc对比

    基本任务:功能测试而测试管理 1.计划说明 本组选择的测试产品A为毕博平台,产品B为中国大学慕课. 项目进度表如下: 2.功能模块 我们小组划分的功能模块如下: 视频.课件的查看 讨论版的使用 提交作 ...

  2. 【神经网络与深度学习-TensorFlow实践】-中国大学MOOC课程(八)(TensorFlow基础))

    [神经网络与深度学习-TensorFlow实践]-中国大学MOOC课程(八)(TensorFlow基础)) 8 TensorFlow基础 8.1 TensorFlow2.0特性 8.1.1 Tenso ...

  3. 【Unity入门教程】 第八章 人工智能【中国大学MOOC游戏引擎原理及应用】

    以下均为来自中国大学mooc 游戏引擎原理及应用时的学习笔记,不含商用,仅供学习交流使用,如果侵权请联系作者删除. 文章目录 8.1 自动寻路 8.2 巡逻 8.3 视野 8.4 自动攻击 8.5 追 ...

  4. Python网络爬虫与信息提取(中国大学mooc)

    目录 目录 Python网络爬虫与信息提取 淘宝商品比价定向爬虫 目标获取淘宝搜索页面的信息 理解淘宝的搜索接口翻页的处理 技术路线requests-refootnote 代码如下 股票数据定向爬虫 ...

  5. 中国大学 MOOC 课程Python语言程序设计 (第11期)测试答案(1-5周)

    中国大学 MOOC 课程Python语言程序设计 (第11期)测试答案(1-5周)  Lan   2020-05-03 14:21   369 人阅读  0 条评论 感谢中国大学MOOC提供的学习平台 ...

  6. python语言使用不需要付费不存在商业风险_中国大学MOOC慕课_Python语言基础与应用_答案...

    中国大学MOOC慕课_Python语言基础与应用_答案 答案: 更多相关问题 下列不属于不得再次公开发行公司债券的情形是(). A.对于公司前一次公开发行的公司债券尚未募足B 从生物电的角度而言,细胞 ...

  7. 慕课乐学python编程题_中国大学MOOC的APP(慕课)2020Python编程基础题目及答案

    中国大学MOOC的APP(慕课)2020Python编程基础题目及答案 更多相关问题 以下哪种细胞类型不是病毒性结膜炎的细胞学特点() 企业在处理非均匀需求过程中,通过那种策略来调整能力满足市场需求的 ...

  8. 计算机技术应用广泛 属于科学计算方面的是,中国大学MOOC: 计算机技术应用广泛,以下属于科学计算方面的是哪个? 答案:火箭轨道计算...

    相关问题 端口的作用是什么? 基于冰山模型的人才选拔模式,在应届生招聘.员工晋升等工作中都会应用,以下属于冰山模型中提到的考察因素的是 创意的结果和过程不一定能够准确面对商业应用,创新则更需要( )和 ...

  9. 算盘在计算机中的应用,中国大学MOOC: 算盘、计算机都是信息处理的工具。

    答案 查看答案 解析: [解析题]当前,应用计算机解决实际问题的能力主要体现为能够熟练使用OFFICE和网页制作工具操作计算机. [解析题]多媒体计算机中的媒体信息是指( ) [解析题]在计算机科学中 ...

最新文章

  1. python项目-2019年5月GitHub上热门的Python项目
  2. php 添加内链插件,ecshop自动内链插件seo优化插件
  3. jquery插件---自动补全类插件
  4. velocity 遍历map
  5. LiveVideoStack线上交流分享 (十七) —— AV1编码器优化与实用落地演进之路
  6. Windows 11 预览版 Build 22000.168 发布
  7. [NOI2005]维护数列 恶心到毁天灭地的splay
  8. H5Plus实用代码片段
  9. eclipse中如何修改编码格式
  10. 天正网络版服务器填写位置,教你如何在天正里面输入坐标定位
  11. CSS类名及常用属性总结
  12. 扩展kalman滤波matlab程序,扩展卡尔曼滤波算法的matlab程序
  13. Android OCR数字识别
  14. 疫情渐消,政策向好,车企的春天要回来了?
  15. 你用过的每款APP都具有这一特点,但你却不知道……
  16. 小金鱼怎么不出来??
  17. Linux下Oracle安装宝典(转)
  18. windows下配置公私钥
  19. python开发office插件_看完这篇Python操作PPT总结,从此使用Python玩转Office全家桶就没有压力了!...
  20. 矩阵特征值和椭圆长短轴的关系?

热门文章

  1. 私域增长 | 私域会员:9大连锁行业15个案例集锦
  2. android 蓝牙4.2.2分析研究
  3. 使用 libcurl 在windows平台遇到的问题
  4. 4.2 APIC 虚拟化
  5. 网络安全之手机安全使用手册
  6. python敲七游戏代码_酒桌上的游戏
  7. 人大金仓windows 10 安装闪退,改绿色安装方法,
  8. MATLAB技术沙龙之如何批量处理图像的大小
  9. 关于三菱RJ71EIP91模块的配置
  10. html 页面地图不显示图片,Html显示地图 - 切切歆语的个人页面 - OSCHINA - 中文开源技术交流社区...