您的位置:首页 > 数码常识数码常识
性能优化Android(android启动优化)
2025-05-10人已围观
性能优化Android(android启动优化)
应用的启动速度对一个APP来说至关重要,会直接影响到用户体验,如果启动速度过慢会导致用户的流失,本文就启动速度优化分析,为优化启动速度提供一些思路。
android启动优化
1、应用启动分类
应用有三种启动状态,每种状态都会影响应用向用户显示所需的时间:冷启动、温启动和热启动。在冷启动中,应用从头开始启动。在另外两种状态中,系统需要将后台运行的应用带入前台。
1.1、冷启动
app冷启动可以分为两个阶段
第一阶段
1、加载并启动app
2、启动后立即显示一个空白的启动窗口
3、创建app进程
第二阶段
1、创建app对象
2、启动主线程
3、创建主Activity
4、加载布局
5、布置屏幕
6、首帧绘制
一旦应用进程完成首帧绘制,系统进程就会换掉当前显示的后台窗口,替换为主Activity。此时,用户可以开始使用应用
冷启动中,作为开发者,能干预的部分主要是Application的OnCreate阶段和Activity的onCreate阶段,如下图:
1.2、热启动
热启动时,系统将activity放到前台。如果应用程序的所有activity存在内存中,则应用程序可以避免重复对象初始化、渲染、绘制操作
1.3、温启动
温启动时,由于app的进程仍然存在,执行的是冷启动的第二阶段
1、创建app对象
2、启动主线程
3、创建主Activity
4、加载布局
5、布置屏幕
6、首帧绘制
温启动常见场景:
1、用户退出应用后又重启应用。进程可能继续运行。但应用从调用Activity的onCreate方法开始重新执行
2、内存不足,系统将应用杀死,然后用户重新启动。进程和Activity需要重启,但传递到onCreate的已保存的实例bundle对于完成启动有一定帮助
接下来来看下如何获得启动时间~
2、获取启动时间2.1、使用adb命令获取
adb shell am start -W [packageName]/[packageName.xxActivity]
ThisTime: 最后一个Activity启动耗时
TotalTime: 启动时经历的所有Activity总耗时
WaitTime: AMS启动所有Activity的总时间(包括启动目标应用前的)
2.2、使用代码打点
该方式一般为Application初始化attachBaseContext方法打启动开始时间戳,应用用户可操作界面完全展示可操作后打结束时间戳,两时间差即为启动耗时
但这种方式并不优雅,如果启动逻辑复杂,方法很多的情况下,最好采用aop进行优化。
3、应用启动优化分析工具3.1、TraceView
Traceview是Android自带的性能分析工具,可图形化展示方法调用时间,调用栈,还可以查看所有线程信息,对分析方法耗时,调用链是非常好的工具
使用方法是采用代码埋点的方式:
1、在开始收集的位置,执行Debug.startMethodTracing("app_trace"),其中参数为自定义文件名
2、在结束收集的位置,执行Debug.endMethodTracing()
文件生成路径为/sdcard/Android/data/包名/files/文件名.trace,使用Android Studio可以打开该文件
举个例子:
我们来看下testAdd这个方法的耗时
运行程序后,找到/sdcard/Android/data/com.restart.perference/files/app_trace.trace文件,在AndroidStudio中双击它,是可以解析出文件中的信息的,打开后如下:
下面来看下,CallChart, FlameChart, Top Down, Bottom Up分别是怎么用的。首先要选择好时间区域,像本案例中,因为程序很简单,能分析的区域比较小,选中它后,可得到下图:
Call Chart得到的图形中,可以看到程序整个调用栈,同时可以看到方法耗时。
比如图中的testAdd方法,先后调用了Debug.startMethodTracing、Log.i、Debug.stopMethodTracing方法。同时从图中可以看出startMethodTracing方法比stopMethodTracing方法耗时长。在实际优化中,找到哪个方法耗时长,针对性优化是非常有作用的。
分析时,第三方程序,系统代码我们一般是优化不了的,CallChart非常贴心地用颜色帮我们区分哪些是我们自己写的代码。橙色的是系统API,蓝色一般是第三方API,绿色的才是我们自己写的。比如图中的testAdd方法,我们自己写的是可以通过调整优化的。
Flame Chart是Call Chart的倒序图,作用相似,图形如下:
Top Down可以看到每个方法内部调用了哪些方法,以及每个方法的耗时,耗时占比,相比于Call Chart的图形查找,Top Down则是更具体,有具体的方法耗时数据
图中的Total代表方法总共的耗时,self代表方法内非方法调用的代码耗时,Children代表方法内调用的其他方法的耗时。
同样以testAdd方法为例,testAdd方法总耗时为3840us,占程序运行时间97%,testAdd方法中自身代码耗时为342us,占比为8.65%,testAdd方法中调用的其他方法总共耗时3498us,占比88.52%
Bottom Up是Top Down的倒序图,可以看方法是被哪个方法调用的
TraceView中还有个选项值得注意,
在右上角有个Wall Clock Time和Thread Time的选项,其中Wall Clock Time的意思是方法执行的实际耗时,而Thread Time指的是CPU耗时。我们平时说的优化更多的是优化CPU时间,当有IO操作时,用Thread Time来分析耗时更合理
此外,使用TraceView需要关注TraceView的运行时开销,因为它自身耗时较长,就有可能会带偏我们的优化方向。
3.2、Systrace
Systrace结合Android内核的数据,生成HTML报告
systrace在Android/sdk/platform-tools/systrace目录中。使用前需要安装python,因为systrace是用python生成html
报告的,命令如下:
具体参数可参考:developer.android.google.cn/studio/prof…
执行命令后,打开报告,显示如下
要使用chrome浏览器打开,否则可能会显示白屏。如果使用chrome也显示白屏,可在chrome浏览器中输入chrome:tracing, 再Load文件进去显示
查看图时,A键是左移,D键右移, S键缩小,W键放大
4、常用优化4.1、启动加载常见优化策略
一个应用越大,涉及模块越多,包含的服务甚至进程就会越多,如网络模块的初始化,底层数据初始化等,这些加载都需要提前准备好,有些不必要的就不要放到应用中。通常可以从以下四个维度整理启动的各个点:
1、必要且耗时:启动初始化,考虑用线程来初始化
2、必要不耗时:不用处理
3、非必要耗时,数据上报、插件初始化,按需处理
4、非必要不耗时:直接去掉,有需要的时候再加载
将应用启动时要执行的内容按上述分类,按需实现加载逻辑。那么常见的优化加载策略有哪些呢?
异步加载:耗时多的加载放到子线程中异步执行
延迟加载: 非必须的数据延迟加载
提前加载:利用ContentProvider提前进行初始化
下面分别介绍异步加载和延迟加载的一些常用处理
4.2、异步加载
异步加载,简单来说,就是使用子线程异步加载。在实际场景中,启动时常常需要对各种第三方库做初始化操作。通过将初始化放到子线程中进行,可以大大加快启动。
但是通常,有些业务逻辑是要再第三方库的初始化后才能正常运行的,这时候如果只是简单的放到子线程中跑,不做限制就很可能出现在没初始化完成就跑业务逻辑,导致异常。
这种较为复杂的情况下,可以采用CountDownLatch处理,或者是使用启动器的思想处理。
CountDownLatch使用
使用CountDownLatch在初始化的逻辑不复杂的情况下推荐使用。但如果初始化的几个库之间又有相互依赖,逻辑复杂的情况下,则推荐使用加载器的方式。
启动器
启动器的核心如下:
充分利用CPU多核能力,自动梳理并顺序执行任务;代码Task化,将启动任务抽象成各个task;根据所有任务依赖关系排序生成一个有向无环图;多线程按照线程优先级顺序执行
具体实现可参考:https://github.com/NoEndToLF/AppStartFaster
4.3、延迟加载
有些第三方库的初始化其实优先级并不高,可以按需加载。或者是利用IdleHandler在主线程空闲的时候进行分批初始化。
按需加载可根据具体情况实现,这里不做赘述。这里介绍下使用IdleHandler的使用
使用IdleHandler做分批初始化,为什么要分批?当主线程空闲时,执行IdleHandler,但如果IdleHandler内容太多,则还是会导致卡顿。因此最好是将初始化操作分批在主线程空闲时进行
4.4、提前加载
上述方案中初始化最快的时机都是在Application的onCreate中进行,但还有更早的方式。ContentProvider的onCreate是在Application的attachBaseContext和onCreate方法中间进行的。也就是说它比Application的onCreate方法更早执行。所以可以利用这点来对第三方库的初始化进行提前加载。
androidx-startup使用
4.5、其他优化
1、在应用中,增加启动默认图或者自定义一个Theme,在Activity首先使用一个默认的界面解决部分启动短暂黑白屏问题。如android:theme="@style/Theme.AppStartLoad"
5、小结
1、冷启动、温启动、热启动主要进行的处理及他们的区别
2、如何获取启动时间,介绍了使用adb命令和代码打点这两种方式
3、如何使用工具找到程序中耗时较长的代码,介绍TraceView和Systrace的使用
4、常见的启动优化方式及实现介绍(异步加载,延迟加载,提前加载等),关键思想:异步、延迟、懒加载
最后
在这里我也分享一份由几位大佬一起收录整理的Flutter进阶资料以及Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料。
这些都是我闲暇时还会反复翻阅的精品资料。可以有效地帮助大家掌握知识、理解原理。当然你也可以拿去查漏补缺,提升自身的竞争力。
上面就是小居数码小编今天给大家介绍的关于(android启动优化)的全部内容,希望可以帮助到你,想了解更多关于数码知识的问题,欢迎关注我们,并收藏,转发,分享。
94%的朋友还想知道的:
将Android联系人共享到iPhone教程(安卓手机如何共享联系人)
软件测试常用的性能测试指标有哪些(软件性能测试有哪些性能指标)
wordpress哪个版本稳定(wordpress性能)
这几款工具能帮到你(新买的电脑怎么检测硬件性能)
153232
应用的启动速度对一个APP来说至关重要,会直接影响到用户体验,如果启动速度过慢会导致用户的流失,本文就启动速度优化分析,为优化启动速度提供一些思路。
android启动优化
1、应用启动分类
应用有三种启动状态,每种状态都会影响应用向用户显示所需的时间:冷启动、温启动和热启动。在冷启动中,应用从头开始启动。在另外两种状态中,系统需要将后台运行的应用带入前台。
1.1、冷启动
app冷启动可以分为两个阶段
第一阶段
1、加载并启动app
2、启动后立即显示一个空白的启动窗口
3、创建app进程
第二阶段
1、创建app对象
2、启动主线程
3、创建主Activity
4、加载布局
5、布置屏幕
6、首帧绘制
一旦应用进程完成首帧绘制,系统进程就会换掉当前显示的后台窗口,替换为主Activity。此时,用户可以开始使用应用
冷启动中,作为开发者,能干预的部分主要是Application的OnCreate阶段和Activity的onCreate阶段,如下图:
1.2、热启动
热启动时,系统将activity放到前台。如果应用程序的所有activity存在内存中,则应用程序可以避免重复对象初始化、渲染、绘制操作
1.3、温启动
温启动时,由于app的进程仍然存在,执行的是冷启动的第二阶段
1、创建app对象
2、启动主线程
3、创建主Activity
4、加载布局
5、布置屏幕
6、首帧绘制
温启动常见场景:
1、用户退出应用后又重启应用。进程可能继续运行。但应用从调用Activity的onCreate方法开始重新执行
2、内存不足,系统将应用杀死,然后用户重新启动。进程和Activity需要重启,但传递到onCreate的已保存的实例bundle对于完成启动有一定帮助
接下来来看下如何获得启动时间~
2、获取启动时间2.1、使用adb命令获取
adb shell am start -W [packageName]/[packageName.xxActivity]
ThisTime: 最后一个Activity启动耗时
TotalTime: 启动时经历的所有Activity总耗时
WaitTime: AMS启动所有Activity的总时间(包括启动目标应用前的)
2.2、使用代码打点
该方式一般为Application初始化attachBaseContext方法打启动开始时间戳,应用用户可操作界面完全展示可操作后打结束时间戳,两时间差即为启动耗时
但这种方式并不优雅,如果启动逻辑复杂,方法很多的情况下,最好采用aop进行优化。
3、应用启动优化分析工具3.1、TraceView
Traceview是Android自带的性能分析工具,可图形化展示方法调用时间,调用栈,还可以查看所有线程信息,对分析方法耗时,调用链是非常好的工具
使用方法是采用代码埋点的方式:
1、在开始收集的位置,执行Debug.startMethodTracing("app_trace"),其中参数为自定义文件名
2、在结束收集的位置,执行Debug.endMethodTracing()
文件生成路径为/sdcard/Android/data/包名/files/文件名.trace,使用Android Studio可以打开该文件
举个例子:
我们来看下testAdd这个方法的耗时
运行程序后,找到/sdcard/Android/data/com.restart.perference/files/app_trace.trace文件,在AndroidStudio中双击它,是可以解析出文件中的信息的,打开后如下:
下面来看下,CallChart, FlameChart, Top Down, Bottom Up分别是怎么用的。首先要选择好时间区域,像本案例中,因为程序很简单,能分析的区域比较小,选中它后,可得到下图:
Call Chart得到的图形中,可以看到程序整个调用栈,同时可以看到方法耗时。
比如图中的testAdd方法,先后调用了Debug.startMethodTracing、Log.i、Debug.stopMethodTracing方法。同时从图中可以看出startMethodTracing方法比stopMethodTracing方法耗时长。在实际优化中,找到哪个方法耗时长,针对性优化是非常有作用的。
分析时,第三方程序,系统代码我们一般是优化不了的,CallChart非常贴心地用颜色帮我们区分哪些是我们自己写的代码。橙色的是系统API,蓝色一般是第三方API,绿色的才是我们自己写的。比如图中的testAdd方法,我们自己写的是可以通过调整优化的。
Flame Chart是Call Chart的倒序图,作用相似,图形如下:
Top Down可以看到每个方法内部调用了哪些方法,以及每个方法的耗时,耗时占比,相比于Call Chart的图形查找,Top Down则是更具体,有具体的方法耗时数据
图中的Total代表方法总共的耗时,self代表方法内非方法调用的代码耗时,Children代表方法内调用的其他方法的耗时。
同样以testAdd方法为例,testAdd方法总耗时为3840us,占程序运行时间97%,testAdd方法中自身代码耗时为342us,占比为8.65%,testAdd方法中调用的其他方法总共耗时3498us,占比88.52%
Bottom Up是Top Down的倒序图,可以看方法是被哪个方法调用的
TraceView中还有个选项值得注意,
在右上角有个Wall Clock Time和Thread Time的选项,其中Wall Clock Time的意思是方法执行的实际耗时,而Thread Time指的是CPU耗时。我们平时说的优化更多的是优化CPU时间,当有IO操作时,用Thread Time来分析耗时更合理
此外,使用TraceView需要关注TraceView的运行时开销,因为它自身耗时较长,就有可能会带偏我们的优化方向。
3.2、Systrace
Systrace结合Android内核的数据,生成HTML报告
systrace在Android/sdk/platform-tools/systrace目录中。使用前需要安装python,因为systrace是用python生成html
报告的,命令如下:
具体参数可参考:developer.android.google.cn/studio/prof…
执行命令后,打开报告,显示如下
要使用chrome浏览器打开,否则可能会显示白屏。如果使用chrome也显示白屏,可在chrome浏览器中输入chrome:tracing, 再Load文件进去显示
查看图时,A键是左移,D键右移, S键缩小,W键放大
4、常用优化4.1、启动加载常见优化策略
一个应用越大,涉及模块越多,包含的服务甚至进程就会越多,如网络模块的初始化,底层数据初始化等,这些加载都需要提前准备好,有些不必要的就不要放到应用中。通常可以从以下四个维度整理启动的各个点:
1、必要且耗时:启动初始化,考虑用线程来初始化
2、必要不耗时:不用处理
3、非必要耗时,数据上报、插件初始化,按需处理
4、非必要不耗时:直接去掉,有需要的时候再加载
将应用启动时要执行的内容按上述分类,按需实现加载逻辑。那么常见的优化加载策略有哪些呢?
异步加载:耗时多的加载放到子线程中异步执行
延迟加载: 非必须的数据延迟加载
提前加载:利用ContentProvider提前进行初始化
下面分别介绍异步加载和延迟加载的一些常用处理
4.2、异步加载
异步加载,简单来说,就是使用子线程异步加载。在实际场景中,启动时常常需要对各种第三方库做初始化操作。通过将初始化放到子线程中进行,可以大大加快启动。
但是通常,有些业务逻辑是要再第三方库的初始化后才能正常运行的,这时候如果只是简单的放到子线程中跑,不做限制就很可能出现在没初始化完成就跑业务逻辑,导致异常。
这种较为复杂的情况下,可以采用CountDownLatch处理,或者是使用启动器的思想处理。
CountDownLatch使用
使用CountDownLatch在初始化的逻辑不复杂的情况下推荐使用。但如果初始化的几个库之间又有相互依赖,逻辑复杂的情况下,则推荐使用加载器的方式。
启动器
启动器的核心如下:
充分利用CPU多核能力,自动梳理并顺序执行任务;代码Task化,将启动任务抽象成各个task;根据所有任务依赖关系排序生成一个有向无环图;多线程按照线程优先级顺序执行
具体实现可参考:https://github.com/NoEndToLF/AppStartFaster
4.3、延迟加载
有些第三方库的初始化其实优先级并不高,可以按需加载。或者是利用IdleHandler在主线程空闲的时候进行分批初始化。
按需加载可根据具体情况实现,这里不做赘述。这里介绍下使用IdleHandler的使用
使用IdleHandler做分批初始化,为什么要分批?当主线程空闲时,执行IdleHandler,但如果IdleHandler内容太多,则还是会导致卡顿。因此最好是将初始化操作分批在主线程空闲时进行
4.4、提前加载
上述方案中初始化最快的时机都是在Application的onCreate中进行,但还有更早的方式。ContentProvider的onCreate是在Application的attachBaseContext和onCreate方法中间进行的。也就是说它比Application的onCreate方法更早执行。所以可以利用这点来对第三方库的初始化进行提前加载。
androidx-startup使用
4.5、其他优化
1、在应用中,增加启动默认图或者自定义一个Theme,在Activity首先使用一个默认的界面解决部分启动短暂黑白屏问题。如android:theme="@style/Theme.AppStartLoad"
5、小结
1、冷启动、温启动、热启动主要进行的处理及他们的区别
2、如何获取启动时间,介绍了使用adb命令和代码打点这两种方式
3、如何使用工具找到程序中耗时较长的代码,介绍TraceView和Systrace的使用
4、常见的启动优化方式及实现介绍(异步加载,延迟加载,提前加载等),关键思想:异步、延迟、懒加载
最后
在这里我也分享一份由几位大佬一起收录整理的Flutter进阶资料以及Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料。
这些都是我闲暇时还会反复翻阅的精品资料。可以有效地帮助大家掌握知识、理解原理。当然你也可以拿去查漏补缺,提升自身的竞争力。
上面就是小居数码小编今天给大家介绍的关于(android启动优化)的全部内容,希望可以帮助到你,想了解更多关于数码知识的问题,欢迎关注我们,并收藏,转发,分享。
94%的朋友还想知道的:
将Android联系人共享到iPhone教程(安卓手机如何共享联系人)
软件测试常用的性能测试指标有哪些(软件性能测试有哪些性能指标)
wordpress哪个版本稳定(wordpress性能)
这几款工具能帮到你(新买的电脑怎么检测硬件性能)
153232
很赞哦! ()
下一篇:返回列表