【笔记】Android应用启动优化

《Android应用启动优化:一种DelayLoad的实现和原理》 :在Android开发中,应用启动速度是一个非常重要的点,应用启动优化也是一个非常重要的过程。对于应用启动优化,其实核心思想就是在启动过程中少做事情,具体实践的时候无非就是下面几种:异步加载、延时加载、懒加载。本文针对延时加载的实现进行了详细分析。

2017年10月25日

性能优化之提高应用启动速度

原理&实践之参考链接:

【原理篇】

Android性能优化典范 - 第6季[胡凯],2016-10-04: http://hukai.me/android-performance-patterns-season-6/

1.App Launch Time & Process, Inspect methods.
从技术角度来说,当用户点击桌面图标开始,系统会立即为这个APP创建独立的专属进程,然后显示启动窗口,直到APP在自己的进程里面完成了程序的创建以及主线程完成了Activity的初始化显示操作,再然后系统进程就会把启动窗口替换成APP的显示窗口。
android_perf_6_launch_time_start_process

上述流程里面的绝大多数步骤都是由系统控制的,一般来说不会出现什么问题,可是对于启动速度,我们能够控制并且需要特别关注的地方主要有三处:

1)Activity的onCreate流程,特别是UI的布局与渲染操作,如果布局过于复杂很可能导致严重的启动性能问题。
2)Application的onCreate流程,对于大型的APP来说,通常会在这里做大量的通用组件的初始化操作。
3)目前有部分APP会提供自定义的启动窗口,这里可以做成品牌宣传界面或者是给用户提供一种程序已经启动的视觉效果。

在正式着手解决问题之前,我们需要掌握一套正确测量评估启动性能的方法。所幸的是,Android系统有提供一些工具来帮助我们定位问题。

1)首先是display time

2)其次是reportFullyDrawn方法

3)然后是Method Tracing

hy备注: Method Tracer was removed in Android Studio 3.0. We can use new CPU Profiler instead. https://developer.android.com/studio/profile/cpu-profiler

使用 Call Chart 标签检查跟踪图示:

在这里插入图片描述

使用 Flame Chart 标签检查跟踪图示:

在这里插入图片描述

4)最后是Systrace

附使用说明: 理解和使用systrace(https://maoao530.github.io/2017/02/06/systrace/)

看官网更靠谱:https://developer.android.google.cn/studio/command-line/systrace

三种方式抓取systrace:

a.通过python脚本

cd android-sdk/platform-tools/systrace (android-sdk请替换为你本机中sdk的路径,可以从)
python systrace.py --time=10 -o mynewtrace.html sched gfx view wm

b.通过Device Monitor (DDMS)

c.自定义systrace,在apk或者framework层添加trace信息

Trace.beginSection(“MyAdapter.onCreateViewHolder”);

Trace.endSection();

使用chrome分析trace.html文件图示 >>>

在这里插入图片描述

Alert直接显示提示信息:

在这里插入图片描述

具体操作图见原文链接。

2.App Launch Time & Activity Creation
提升Activity的创建速度是优化APP启动速度的首要关注目标。从桌面点击APP图标启动应用开始,程序会显示一个启动窗口等待Activity的创建加载完毕再进行显示。在Activity的创建加载过程中,会执行很多的操作,例如设置页面的主题,初始化页面的布局,加载图片,获取网络数据,读写Preference等等。
在这里插入图片描述
android_perf_6_activity_creation_0

上述操作的任何一个环节出现性能问题都可能导致画面不能及时显示,影响了程序的启动速度。上一个段落我们介绍了使用Method Tracing来发现那些耗时占比相对较多的方法。假设我们发现某个方法执行时间过长,接下去就可以使用Systrace来帮忙定位到底是什么原因导致那个方法执行时间过长。

除了使用工具进行具体定位分析性能问题之外,以下两点经验可以帮助我们对Activity启动做性能优化:

1)优化布局耗时:一个布局层级越深,里面包含需要加载的元素越多,就会耗费更多的初始化时间。关于布局性能的优化,这里就不展开描述了!
2)异步延迟加载:一开始只初始化最需要的布局,异步加载图片,非立即需要的组件可以做延迟加载。

3.App Launch Time & Bloated Application Objects
绝大多数全局组件的初始化操作都放在Application的onCreate里面,但其实很多组件是需要做区别对待的,有些可以做延迟加载,有些可以放到其他的地方做初始化操作,特别需要留意包含Disk IO操作,网络访问等严重耗时的任务,他们会严重阻塞程序的启动。

android_perf_6_application_lazyload
在这里插入图片描述

4.App Launch Time & Theme Launch Screens
启动闪屏,只是使用『障眼法』弱化了用户对启动时间的感知,正确的使用方法是自定义一张图片,把这张图片通过设置主题的方式显示为启动闪屏,代码执行到主页面的onCreate的时候设置为程序正常的主题。


2018.6.14首次整理记录.

Android 开发之 App 启动时间统计,2016-8-10:https://www.jianshu.com/p/c967653a9468

通常来说,在安卓中应用的启动方式分为以下几种:

冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动。冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化 Application 类,再创建和初始化 MainActivity 类,最后显示在界面上。

热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。热启动因为会从已有的进程中来启动,所以热启动就不会走 Application 这步了,而是直接走 MainActivity,所以热启动的过程不必创建和初始化 Application,因为一个应用从新进程的创建到进程的销毁,Application 只会初始化一次。

首次启动:首次启动严格来说也是冷启动,之所以把首次启动单独列出来,一般来说,首次启动时间会比非首次启动要久,首次启动会做一些系统初始化工作,如缓存目录的生产,数据库的建立,SharedPreference的初始化,如果存在多 dex 和插件的情况下,首次启动会有一些特殊需要处理的逻辑,而且对启动速度有很大的影响,所以首次启动的速度非常重要,毕竟影响用户对 App 的第一映像。

本地调试可使用命令行:

adb shell am start -W packagename/activitypath

在线调试需要在关键点加Log, 时间点的选择依据如下

应用主要启动流程:

通过 Launcher 启动应用时,点击应用图标后,Launcher 调用 startActivity 启动应用。
Launcher Activity 最终调用 Instrumentation 的 execStartActivity 来启动应用。
Instrumentation 调用 ActivityManagerProxy (ActivityManagerService 在应用进程的一个代理对象) 对象的 startActivity 方法启动 Activity。
到目前为止所有过程都在 Launcher 进程里面执行,接下来 ActivityManagerProxy 对象跨进程调用 ActivityManagerService (运行在 system_server 进程)的 startActivity 方法启动应用。
ActivityManagerService 的 startActivity 方法经过一系列调用,最后调用 zygoteSendArgsAndGetResult 通过 socket 发送给 zygote 进程,zygote 进程会孵化出新的应用进程。
zygote 进程孵化出新的应用进程后,会执行 ActivityThread 类的 main 方法。在该方法里会先准备好 Looper 和消息队列,然后调用 attach 方法将应用进程绑定到 ActivityManagerService,然后进入 loop 循环,不断地读取消息队列里的消息,并分发消息。
ActivityManagerService 保存应用进程的一个代理对象,然后 ActivityManagerService 通过代理对象通知应用进程创建入口 Activity 的实例,并执行它的生命周期函数。
-> Application 构造函数 -> Application.attachBaseContext() -> Application.onCreate() -> Activity 构造函数 -> Activity.setTheme() -> Activity.onCreate() -> Activity.onStart -> Activity.onResume -> Activity.onAttachedToWindow -> Activity.onWindowFocusChanged

记录冷启动启动时间一般可以在 Application.attachBaseContext() 开始的位置记录起始时间点,记录热启动启动时间点可以在 Activity.onRestart() 中记录起始时间点。

应用启动的结束时间点在 Activity.onWindowFocusChanged 记录。

【实践篇】

Android性能优化(一)之启动加速35%,2017-1-10:https://juejin.im/post/5874bff0128fe1006b443fa0

懒加载、

视图层级过深、

大量资源初始化、

异步初始化三方组件,不阻塞主线程,延迟到使用前再初始化,

Multidex的使用,也是拖慢启动速度的元凶,

【TODO】Need 实践排查耗时所在。

Android端应用秒开优化体验,2016-7-18:http://zhengxiaoyong.me/2016/07/18/Android端应用秒开优化体验/

解决任务在界面绘制前过于集中化。

应用启动过程从用户点击launcher图标到看到第一帧这个过程:

main()->Application:attachBaseContext()->onCreate()->Activity:onCreate()->onStart()->onPostCreate()->onResume()->onPostResume()

界面开始绘制是在onResume()方法开始后才开始绘制。此处onPostResume的关注点与上上篇onWindowFouceChanged有出入。

Activity的创建都会辗转到ActivityThread:performLaunchActivity()这个方法中,在这个方法中可以知道这么几件事:
1、先通过Instrumentation:newActivity()来创建一个Activity实例
2、再判断Application实例是否已创建,已创建则直接返回,否则调用 Instrumentation:newApplication() 来创建Application实例,在这个过程中会依次执行attachBaseContext()和onCreate()方法
3、之后Activity:attach()方法会创建一个PhoneWindow对象,它就是界面,它有一个DecorView,调用setContentView()时会给配置DecorView,其中就会设置一个背景
4、最后依次调用Activity的onCreate、onStart等方法

优化措施:
1、任务分级
2、任务并行
3、界面预显示

可以对任务进行分级的临界点可以这样分:
1、CoreSDK——Application的创建
2、HighPrioritySDK——Activity的创建
3、LowPrioritySDK——Activity界面完成绘制
4、AsyncSDK——Activity的创建

launch
分级带来的问题:
正常启动过程那肯定是没问题的,不过有这么几种场景:

1、App切回后台,内存不足导致Application被回收,从最近任务列表中恢复界面时Application需重新创建
2、应用没挂起时,Push推送需从Notification跳入应用内某界面
3、应用没挂起时,浏览器外链需跳入应用内某界面

这些Case可能导致的问题是被跳入的界面使用到了未初始化的SDK,可能导致Crash或者数据异常,所以目标页面启动前必须确保SDK已经初始化,这个过程的原因是没有唤起启动页来初始化SDK,可以通过hook newActivity解决,其中判断Application是否初始化和各个SDK是否初始化,并且判断该次启动不来自系统的Launcher。


2018年6月22日 整理.

这个记录已经过时,建议重新梳理这个优化需要做的工作.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值