欢迎来到 Android 开发老生常谈的性能优化篇,本文将性能优化划分为内存、网络、布局、卡顿、安装包、启动速度六块,从这六块优化出发,阐述优化的 Application 的方式。
在 Android 中,内存优化通常指的是 运行内存优化。运行内存优化 主要关注如何有效地使用和管理应用程序的 RAM (Random Access Memory) 使用,以提高性能,减少延迟,并防止应用程序因为消耗过多内存而被系统杀死。
内存泄漏是指应用程序分配了内存,但未能释放。这会导致应用程序消耗的内存随着时间的推移而增加,可能导致应用程序崩溃或系统性能下降。
Android Studio 提供了一些工具,如 Memory Profiler,可以帮助开发者分析和理解应用程序的内存使用情况。
使用更有效的数据结构和算法可以减少内存使用。
合理使用 数据库、网络、图片缓存数据,可以减少不必要的数据、重复数据的存储,减少数据创建和销毁的开销,此外,还可以提高数据的访问速度。
垃圾回收 (Garbage Collection 简称 GC) ,频繁的垃圾回收会影响应用程序的性能。可以通过减少对象的创建和销毁,以及使用对象池等技术来减少垃圾回收的频率。
尽可能地减少网络请求次数,可以通过合并请求、使用批量接口等方式实现。
对于一些不经常变动的数据,可以使用缓存来减少网络请求。例如,可以使用 HTTP 缓存、数据库缓存或者内存缓存。
例如,对于大量的数据,可以使用 Protobuf 而不是 JSON,因为 Protobuf 更加紧凑,可以减少数据的大小,从而减少网络传输的时间。
使用 OkHttp、Retrofit 等网络库,它们内部已经做了很多优化。
对于一些不需要立即返回结果的操作,可以使用后台同步,例如使用 WorkManager 或者 JobScheduler。
对于一些用户可能需要的数据,可以提前进行加载。
使用 HTTP2,它们支持多路复用,可以减少连接的建立和关闭的开销。
对于图片,可以使用合适的格式和大小,还可以使用图片加载库,例如 Glide 或者 Picasso,它们内部已经做了很多优化。
在进行网络请求前,先检测网络状态,如果网络不可用,那么可以立即返回错误,而不是等待超时。
在 Android 系统中,每一秒屏幕刷新速度为 60 帧(FPS),人类眼睛舒适放松时的可视帧率是 24 帧,当某个加载中的界面每秒刷新低于 24 帧时,就会感觉到卡顿。但当屏幕没有绘制需求时,即屏幕的显示的界面为静止时,帧率为 0。
如果在主线程(UI线程)中执行了耗时的操作,如网络请求、数据库操作等,会导致UI更新延迟,从而引发卡顿。
如果应用中存在内存泄漏,可能会导致内存占用过高,从而引发卡顿。
如果布局层级过深或者布局过于复杂,可能会导致布局渲染时间过长,从而引发卡顿。
如果Bitmap对象过大,可能会导致内存占用过高,从而引发卡顿。
垃圾回收 (Garbage Collection 简称 GC) 过程需要消耗系统资源,如果频繁触发,可能会导致应用性能下降,出现卡顿现象。
可以使用线程、协程、AsyncTask等技术将耗时操作移至后台执行。
尽量减少布局的层级,避免过度绘制,使用更高效的 View 或 ViewGroup。
使用
LeakCanary等工具帮助找到并处理内存泄漏。
尽量不要使用过大的
Bitmap,使用合适的压缩格式和分辨率,及时回收不再使用的Bitmap。
尽量减少内存抖动,避免频繁的对象创建和销毁。 内存抖动 (
Memory Churn) 是指应用程序在短时间内频繁地创建和销毁对象,这种行为会导致垃圾回收器 (Garbage Collector) 频繁地运行,从而消耗大量的CPU资源,可能导致应用程序的性能下降,出现卡顿现象。
以上只是一些可能的原因,具体的原因需要通过性能分析工具如 Android Profiler、BlockCanary、Systrace 等进行分析。
删除多余的so库,执行这一操作的前提是:程序所运行的系统 CPU 架构固定是 Android CPU 架构中的某一个。例如:部分第三方提供的 so 库是包含了 armeabi、armeabi-v71、arm64-v8a、x86 等库文件,如果你的程序只运行在 armeabi CPU 架构上,则可以把其它的 so 库文件删除。
mipmap 文件夹。一般图标资源使用 mipmap-xhdpi 足够用了,更大的屏幕则使用 mipmap-xxhdpi 、mipmap-xxxhdpi 的分辨率,已经使用 mipmap-xhdpi 或其它更大分辨率的程序,应删除比它小的分辨率文件。
可通过 Android Studio 菜单栏的 Refactor → Remove Unused Resources 功能一键移除未被使用的 drawable、mipmap、layout 以及 colors.xml、strings.xml 文件里面的 color、string。
.so 文件可以在用户安装应用到手机后再从服务器上下载到手机的 data 目录下,加载的时候使用绝对路径在 static 关键字里加载。
static {
System.loadLibrary("so文件")
}
参考文章
1、Android 应用资源概述
插件化技术支持动态加载代码和动态加载资源,把 Application 的一部分分离出来,对于业务庞大的项目非常有用,极大的分解了 Application 的大小。但又因为插件化需要一定的技术保障和服务端的系统支持,有一定的风险,建议酌情选择。
代码混淆(Obfuscation)是将计算机程序的源代码或机器代码,转换成功能上等价,但是难于阅读和理解的形式的行为。简单来说,就是简化函数名、变量、常量名称,通过减少字符数以达到减小安装包大小的方式。
启用混淆只需要打开 Android 项目,在 Application Model 下中找到 build.gradle,在该文件添加如下配置即可开启混淆:
android {
// 打包 release 包时执行
release {
// 启用混淆,默认使用 R8 编译器
minifyEnabled true
// 资源压缩
shrinkResources true
// 定义 自定义混淆规则的文件
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
上面混淆的方式仅适用于代码简单、封装少的项目。项目复杂还请自定义混淆规则,详情请查看往期文章👉【Android】App攻防之代码混淆
App Startup 是 Android 官方推出的一个应用程序启动时初始化组件的库。开发人员可以使用 App Startup 来简化启动序列并显式设置初始化顺序。
详情请看👉 App Startup
懒加载是一种延迟加载的策略,它指的是在需要时才进行加载和初始化,而不是在应用程序启动或页面加载时就提前加载。这种策略通常用于延迟加载大型资源或组件,以减少启动时间和内存占用。
详情请看👉 ViewStup
详情请看👉 Paging
详情请看👉 ViewPager 2
预加载是在应用程序启动或特定页面加载之前提前加载和准备数据、资源或组件。这有助于提高应用程序的性能和响应速度,因为一些必要的内容已经被提前加载到内存中,而不是等到用户请求时再进行加载。
伪加载是一种虚假的加载行为,通常用于模拟加载过程而不实际进行真正的加载。这种策略可以用于创建加载动画或展示加载状态,以提升用户体验,但实际上并没有进行真实的加载操作。
给 app 添加启动页,这应该是最常见的实现伪加载的方式了。当应用启动页播放完成跳转到首页时,你能很明显的感觉到,app 比没有使用启动页之前变得更“流畅”了。
设置启动页参考文章 👉 Android—启动页+闪屏页
其它启动速度优化的方法:
1、尽量不要在Application的onCreate中写初始化代码
2、减少静态类、静态方法、静态函数的使用,尽量做到用时再初始化
在 Android 中,我们可以通过 adb 命令:adb shell am start -W packageName/packageName.ActivityName 获取到启动该 Activity 所消耗的时间,如下:
E:\Projects\StepDemo> adb shell am start -W com.binyouwei.demo/com.binyouwei.demo.MainActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.binyouwei.demo/.MainActivity }
Status: ok
Activity: com.binyouwei.demo/.MainActivity
ThisTime: 522
TotalTime: 522
WaitTime: 525
Complete
在上方,我输入了 adb shell am start -W com.binyouwei.demo/com.binyouwei.demo.MainActivity ,系统给我响应了一大串的字符,其中的含义如下:
ThisTime:指定的 activity 启动耗时。
TotalTime:应用自身启动耗时 = ThisTime + 应用 Application 等资源启动时间
WaitTime:系统启动应用耗时 = TotalTime + 系统资源启动时间
使用 WorkManager 实现后台保活,当应用处于后台时,应用所占的内存不会被系统完全回收,再次启动应用相较于第一次启动会更快。
冷启动是指应用程序从头开始启动的过程,这意味着应用程序的进程被终止,用户点击应用图标重新启动应用。在冷启动过程中,应用需要重新创建进程、初始化应用程序和加载 UI 界面。
温启动是指应用程序在后台保持活动状态并且重新进入前台时的启动方式。在温启动过程中,应用程序的进程仍然存在,但需要重新初始化和加载 UI 界面。
热启动是指应用程序在后台保持活动状态并且重新进入前台时的快速启动方式。在热启动过程中,应用程序的进程仍然存在,并且可以快速恢复到之前的状态,而不需要重新初始化和加载 UI 界面。