说到安卓性能优化,这个话题实在是很广,之前在上上一家公司专门搞了一段时间的优化,发现APP的各个方面都得到性能上的提升,为此老板还给我奖励了1000块钱。时间久了不去回顾,加上技术的日新月异,打算把自己积累的经验重新整理回顾,不放在为知笔记了,太难找了,暂且分几个专题详解:
1.启动的优化
2.布局的优化
3.内存的优化
4.电量的优化
5.卡顿的优化
6.流量的优化
启动的优化
启动缓慢导致的黑屏,白屏问题,大部分的答案都是做一个透明的主题,或者是做一个Splash界面,这就是我在之前公司的临时方案。
APK启动原理
APK的启动方式
1.冷启动
后台没有该应用的进程,这时系统会首先会创建一个新的进程分配给该应用
由于冷启动过程中,系统和APP的许多工作都要重新开始,所以一般而言这种启动方式是最慢且最具有挑战性的。除了创建和初始化Application和MainActivity之外,冷启动还要加载主题样式Theme,inflate布局,setContentView ,测量、布局、绘制以后显示,我们才看到了屏幕的第一帧
也就是说当用户点击你的app那一刻到系统调用Activity.onCreate()之间的这个时间段内,WindowManager会先加载app主题样式中的windowBackground做为app的预览元素,然后再真正去加载activity的layout布局。
为什么会出现黑屏白屏呢?
系统进程在创建Application的过程中会产生一个BackgroudWindow,等到App完成了第一次绘制,系统进程才会用MainActivity的界面替换掉原来的BackgroudWindow
很显然,如果你的application或activity启动的过程太慢,导致系统的BackgroundWindow没有及时被替换,就会出现启动时白屏或黑屏的情况(取决于你的主题是Dark还是Light)
冷启动优化
1.主题替换
我们在style中自定义一个样式Lancher,在其中放一张背景图片,或是广告图片之类的
1. <style name="AppTheme.Launcher">
2. <item name="android:windowBackground">@drawable/bg</item>
3. </style>
把这个样式设置给启动的Activity
1. <activity
2. android:name=".activity.SplashActivity"
3. android:screenOrientation="portrait"
4. android:theme="@style/AppTheme.Launcher"
5. >
然后在Activity的onCreate方法,把Activity设置回原来的主题
1. @Override
2. protected void onCreate(Bundle savedInstanceState) {
3. //替换为原来的主题,在onCreate之前调用
4. setTheme(R.style.AppTheme);
5. super.onCreate(savedInstanceState);
6. }
这样在启动时就通过给用户看一张图片或是广告来防止黑白屏的尴尬。
还一种方式,就是把windowBackground属性设为null,这样在启动时,backgroundWindow的背景就会变成透明的,给人的感觉就是点了应用图标以后,延迟了一会儿然后加载第一个activity的界面。
1. <style name="AppTheme.Launcher">
2. <item name="android:windowBackground">@null</item>
3. </style>
第二种方式可能会出现黑屏,第一种的图要选取好,不然也会有突兀感,所以很多公司都选择就让他白屏,改变主题实际上是一种伪优化,因为它实质上并没有真正减少App启动的时间
另外还可以设置style
<style name="LaunchStyle" parent="AppTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
</style>
或者
<item name="android:windowDisablePreview">true</item>
这个就是直接甩锅个系统
其他方法 就是进入后直接动画,或者是MD模式的效果, GitHub 上的开源项目 saulmm/onboarding-examples-android
Application是程序的主入口
延迟初始化,后台任务,界面预加载
在Application的构造器方法、attachBaseContext()、onCreate()方法中不要进行耗时操作的初始化,一些数据预取放在异步线程中。
数据库,IO操作,密集网络请求不要放在Application的构造方法中,能使用工作线程的尽量使用工作线程,不要在Application的onCreate中创建线程池,因为那样会有比较大的开销,可以考虑延后再创建。
第三方SDK如果主线程中没有立即使用,可以考虑延迟几秒再初始化,总之一句话,尽早让用户看到应用的界面,其他操作都可以先让路。
对于MainActivity,由于在获取到第一帧前,需要对contentView进行测量布局绘制操作,尽量减少布局的层次,考虑StubView的延迟加载策略,当然在onCreate、onStart、onResume方法中避免做耗时操作
- MultiDex以及Tinker的初始化,最先执行;关于MultiDex的优化本文不再赘述,参考我之前Multidex的系列文章。
- Application中主要做了各种三方组件的初始化;
项目中除听云之外其余所有三方组件都抢占先机,在Application主线程初始化。这样的初始化方式肯定是过重的:
- 考虑异步初始化三方组件,不阻塞主线程;
- 延迟部分三方组件的初始化;实际上我们粗粒度的把所有三方组件都放到异步任务里,可能会出现WorkThread中尚未初始化完毕但MainThread中已经使用的错误,因此这种情况建议延迟到使用前再去初始化;
- 而如何开启WorkThread同样也有讲究,这个话题在下文详谈。
项目修改:
- 将友盟、Bugly、听云、GrowingIO、BlockCanary等组件放在WorkThread中初始化;
- 延迟地图定位、ImageLoader、自有统计等组件的初始化:地图及自有统计延迟4秒,此时应用已经打开;而ImageLoader
因为调用关系不能异步以及过久延迟,初始化从Application延迟到SplashActivity;而EventBus因为再Activity中使用所以必须在Application中初始化
2.温启动
一台已有该应用的进程,但是启动的入口Activity被干掉了,比如按了back键,应用虽然退出了,但是该应用的进程是依然会保留在后台
3.热启动
一后台已有该应用的进程,比如按下home键,这种在已有进程的情况下,这种启动会从已有的进程中来启动应用
应用的启动时间统计
在现在的公司最近还在搞启动优化,提供2种方式
1.查看启动时间adb 命令
adb shell am start -W [PackageName]/[PackageName.XX.XXXActivity]
这个PackageName 需要你到你自己项目的清单文件去自己找,输入adb命令后,程序会等待你启动然后在统计这个时间,
ThisTime:最后一个启动的Activity的启动耗时; ThisTime:一般和TotalTime时间一样,我们的是中间开了一个
TotalTime:自己的所有Activity的启动耗时;包括创建进程+Application初始化+Activity初始化到界面显示
WaitTime: ActivityManagerService启动App的Activity时的总时间(包括当前Activity的onPause()和自己Activity的启动)一般比TotalTime大点,包括系统影响的耗时
2.使用Android Studio 的日志,在过滤框输入display
然后清空日志,然后启动如下:
Application开始到首页显示出来
Application的构造器方法——>attachBaseContext()——>onCreate()——>Activity的构造方法——>onCreate()——>配置主题中背景等属性——>onStart()——>onResume()——>测量、布局、绘制显示在界面上
上面这些阶段全部都是在主线程中执行的,任何不经意的操作都可能拖慢应用的启动速度。所以我们不应在Application以及Activity的生命周期回调中做任何费时操作,具体指标大概是你在onCreate,onResume,onStart等回调中所花费的总时间最好不要超过400ms,否则用户在桌面点击你的应用图标后,将感觉到明显的卡顿
针对上面的需求,一般处理是将任务分优先级启动,应用启动开始加载 ;首页渲染后加载;渲染后延迟加载
具体延迟多久 在性能好的手机上面启动非常快,很短的延迟就行了,但是在低端手机上缺很慢,还要为了兼容久手机,一般延长很长的时间,
第一种写法:直接PostDelay 300ms.
myHandler.postDelayed(mLoadingRunnable, DEALY_TIME);
第二种写法:优化的DelayLoad
getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
myHandler.post(mLoadingRunnable);
}
});
第二种,在窗口完成以后进行加载,这里面的run方法是在onResume之后运行的具体参考这个:http://www.androidperformance.com/2015/11/18/Android-app-lunch-optimize-delay-load.html
启动优化思路
1、UI渲染优化,去除重复绘制,减少UI重复绘制时间,打开设置中的GPU过度绘制开关,各界面过度绘制不应超过2.5x;也就是打开此调试开关后,界面整体呈现浅色,特别复杂的界面,红色区域也不应该超过全屏幕的四分之一;
2、根据优先级的划分,KoMobileApplication的一些初始化工作能否将任务优先级划分成3,在首页渲染完成后进行加载,比如:PaySDKManager。
3、主线程中的所有SharedPreference能否在非UI线程中进行,SharedPreferences的apply函数需要注意,因为Commit函数会阻塞IO,这个函数虽然执行很快,但是系统会有另外一个线程来负责写操作,当apply频率高的时候,该线程就会比较占用CPU资源。类似的还有统计埋点等,在主线程埋点但异步线程提交,频率高的情况也会出现这样的问题。
4、检查BaseActivity,不恰当的操作会影响所有子Activity的启动。
5、对于首次启动的黑屏问题,对于“黑屏”是否可以设计一个.9图片替换掉,间接减少用户等待时间。
6、对于网络错误界面,友好提示界面,使用ViewStub的方式,减少UI一次性绘制的压力。
7、任务优先级为2,3的,通过下面这种方式进行懒加载的方式
getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
myHandler.post(mLoadingRunnable);
}
});
8、Multidex的使用,也是拖慢启动速度的元凶,必须要做优化。后面有空专门写一篇Multidex
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。 相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
一、架构师筑基必备技能
1、深入理解Java泛型 2、注解深入浅出 3、并发编程 4、数据传输与序列化 5、Java虚拟机原理 6、高效IO ……
二、Android百大框架源码解析
1.Retrofit 2.0源码解析 2.Okhttp3源码解析 3.ButterKnife源码解析 4.MPAndroidChart 源码解析 5.Glide源码解析 6.Leakcanary 源码解析 7.Universal-lmage-Loader源码解析 8.EventBus 3.0源码解析 9.zxing源码分析 10.Picasso源码解析 11.LottieAndroid使用详解及源码解析 12.Fresco 源码分析——图片加载流程
三、Android性能优化实战解析
-
腾讯Bugly:对字符串匹配算法的一点理解
-
爱奇艺:安卓APP崩溃捕获方案——xCrash
-
字节跳动:深入理解Gradle框架之一:Plugin, Extension, buildSrc
-
百度APP技术:Android H5首屏优化实践
-
支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
-
携程:从智行 Android 项目看组件化架构实践
-
网易新闻构建优化:如何让你的构建速度“势如闪电”?
-
…
四、高级kotlin强化实战
1、Kotlin入门教程 2、Kotlin 实战避坑指南 3、项目实战《Kotlin Jetpack 实战》
-
从一个膜拜大神的 Demo 开始
-
Kotlin 写 Gradle 脚本是一种什么体验?
-
Kotlin 编程的三重境界
-
Kotlin 高阶函数
-
Kotlin 泛型
-
Kotlin 扩展
-
Kotlin 委托
-
协程“不为人知”的调试技巧
-
图解协程:suspend
五、Android高级UI开源框架进阶解密
1.SmartRefreshLayout的使用 2.Android之PullToRefresh控件源码解析 3.Android-PullToRefresh下拉刷新库基本用法 4.LoadSir-高效易用的加载反馈页管理框架 5.Android通用LoadingView加载框架详解 6.MPAndroidChart实现LineChart(折线图) 7.hellocharts-android使用指南 8.SmartTable使用指南 9.开源项目android-uitableview介绍 10.ExcelPanel 使用指南 11.Android开源项目SlidingMenu深切解析 12.MaterialDrawer使用指南
六、NDK模块开发
1、NDK 模块开发 2、JNI 模块 3、Native 开发工具 4、Linux 编程 5、底层图片处理 6、音视频开发 7、机器学习
七、Flutter技术进阶
1、Flutter跨平台开发概述 2、Windows中Flutter开发环境搭建 3、编写你的第一个Flutter APP 4、Flutter开发环境搭建和调试 5、Dart语法篇之基础语法(一) 6、Dart语法篇之集合的使用与源码解析(二) 7、Dart语法篇之集合操作符函数与源码分析(三) …
八、微信小程序开发
1、小程序概述及入门 2、小程序UI开发 3、API操作 4、购物商场项目实战……
全套视频资料:
一、面试合集 二、源码解析合集
三、开源框架合集
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取【保证100%免费】↓↓↓
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/8710.html