Android性能优化工具的使用

2字数 3908阅读 1474

因为众所周知的原因,Android APP总是需要调优,今天笔者就介绍一下Google工程师提供给我们的优化工具以及如何使用他们查找解决性能问题的方法。
一般来说,APP主要的就是往以下四个方面优化,各种调优,优化,都是奔着这四个方面去。


主要方面

1 ANDROID优化工具的使用

1.1 Profile

Android Stduio3.1之后就取消了DeviceMonitor,开始全面使用Profile,而Profile又细分了三个方面,慢慢来介绍

1.1.1 CPU Profile 让你的APP更快

AS为我们自动创建了两个CPU Profile的默认配置,一个是Sample Java Method,另一个是Trace Java Method,而这两者之间有什么区别呢?
最主要的区别就是:Sample 会频繁的捕捉调用堆栈以获取具体信息。而Trace则是在每个函数开始之前跟结束之后记录时间戳,然后分析数据。
举个例子,

fun add(int a ,int b):int = a+b

函数A仅仅执行一个加法运行,运行时间非常短暂,那么如果Sample恰好在进入此函数之前捕捉了一次堆栈信息且在此函数退出后,又捕捉了一次堆栈信息,那么A函数则不会被分析器记录。而Trace则不同,Trace是在每个函数开始之前与结束之后记录时间戳,所以不会错失任何一次函数调用,但是Trace的问题就在于,频繁记录很可能会超出记录文件限定的大小(默认为8M)
所以如何取舍,还是要看自己。

CPU Profile

1 选择时间范围: 用于确定您要在跟踪窗格中检查所记录时间范围的哪一部分。 首次记录函数跟踪时,CPU Profiler 将在 CPU 时间线中自动选择记录的完整长度。如果只想记一小部分,则可以使用自主选择
2 时间戳: 用于表示所记录函数跟踪的开始和结束时间(相对于分析器从设备开始收集 CPU 使用率信息的时间)。 在选择时间范围时,您可以点击时间戳以自动选择完整记录,如果您有多个要进行切换的记录,则此做法尤其有用。
3 跟踪窗格: 用于显示您所选的时间范围和线程的函数跟踪数据。 仅在您至少记录一个函数跟踪后此窗格才会显示。 在此窗格中,您可以选择想如何查看每个堆叠追踪(使用跟踪标签),以及如何测量执行时间(使用时间引用下拉菜单)。
4 选择后,可通过 Top Down 树、Bottom Up 树、调用图表或火焰图的形式显示您的函数跟踪。 您可以在下文中了解每个跟踪窗格标签的更多信息。
从下拉菜单中选择以下选项之一,以确定如何测量每个函数调用的时间信息:
5 Wall clock time:壁钟时间信息表示实际经过的时间。
6 Thread time:线程时间信息表示实际经过的时间减去线程没有消耗 CPU 资源的任意时间部分。 对于任何给定函数,其线程时间始终少于或等于其壁钟时间。 使用线程时间可以线程的实际 CPU 使用率中有多少是给定函数消耗的。

其又分四个具体标签,分别是Call Chart,Flame Chart,Top Down,Bottom Up
Call Chart跟Flame Chart都是图标形式的体现,一个是顺序调用,一个是逆序


Call Chart
Flame Chart

Top Down,Bottom Up也与其类似,不过都是函数具体调用,一个是从上至下,一个是自低向上


Top Down

Bottom Up

最简单区分方法就是:TopDown 与 Call Chart都是从main函数开始,往下记录被调用函数,而Flame Chart跟Bottom Up则是从底层函数开始回溯。

总结:CPU Profile可帮助我们分析程序具体哪个函数耗时最多,最影响性能,右键跳转源码,可直接定位到具体代码。

1.1.2 Memory Profile 让你的APP更稳

性能优化的重中之中,内存分析器,自从有了APP显示Bitmap, OOM就是最让人蛋疼的异常错误,因为不仅要修改大小,还要优化代码,压缩bitmap。
而如今,我们可以借助Memory Profile来分析。大名鼎鼎的leakCanary也是根据hprof文件来对比分析定位是否有内存泄漏。

Memory Profile

内存计数中的类别如下所示:

  • Java:从 Java 或 Kotlin 代码分配的对象内存。(这个对象就是我们主要关注的,代码申请的对象总大小)
  • Native:从 C 或 C++ 代码分配的对象内存。Framwork层的对象
  • Graphics:图形缓冲区队列向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。 (android系统16ms发送一次Vsync信号,通知GPU渲染数据,这份是GPU专用用来存储未渲染的数据队列)
  • Stack:应用中的原生堆栈和 Java 堆栈使用的内存。 这通常与应用运行多少线程有关。(申请的堆栈内存)
  • Code:应用用于处理代码和资源(如 dex 字节码、已优化或已编译的 dex 码、.so 库和字体)的内存。
  • Other:应用使用的系统不确定如何分类的内存。
  • Allocated:应用分配的 Java/Kotlin 对象数。 它没有计入 C 或 C++ 中分配的对象。


    heapDump
将堆转储另存为 HPROF

用来查看具体分配的对象以及占据的内存大小,不过heapDump文件不是永久的,如果想要保存下来还使用 Export heap dump as HPROF file!
,将堆转储导出到一个 HPROF 文件中。下次再打开就可以直接使用了。

检测内存泄漏

以前有Device Monitor咱们是先存储一次hprof文件,然后频繁操作再频繁gc,再来保存一次hprof文件,然后用Mat工具对比查看两个文件是否有大的区别,而如今Google又介绍了一个简单的,查看是否有内存泄漏的方法:

  • 将设备从纵向旋转为横向,然后在不同的 Activity 状态下反复操作多次。 旋转设备经常会导致应用泄漏 Activity,Context或 View 对象,因为系统会重新创建 Activity,而如果您的应用在其他地方保持对这些对象之一的引用,系统将无法对其进行垃圾回收。
  • 处于不同的 Activity 状态时,在您的应用与另一个应用之间切换(导航到主屏幕,然后返回到您的应用)

1.1.3 NetWork Profile

分析应用网络使用情况,由于现在一般不太在乎网络的使用情况,毕竟5G时代马上来临,所以这部分暂时搁置,各位同学有兴趣的可以自己研究如何使用。

1.2 Lint

Analyzer->Inspect Code 即可启用Lint

Lint检测结果

1.2.1 辅助功能 Accessibility

重要指数:一般
一般指的是控件该有的标签没有,比如ImageView的android:contentDescription 属性,这个标签主要是给盲人用的,Google Assistant会根据这个属性的值来帮助盲人理解。如果有兴趣的同学可以自己继续研究。

1.2.2 健壮性 Correctness 让你的APP更稳

重要指数:重要
一般会提示四大组件 比如Activity跟Service等没有注册,影响APK被PKMS解析
代码使用方面的问题,如果使用了Private API则会提示将来不支持,会引起异常崩溃,想必大家都体验过在XX机型上莫名其妙的Crash问题,所以这个标签下的内容大家一定要注意检查,务必使其消失。

1.2.3 国际化 Internationalzation

重要指数:一般
顾名思义,这个是为了以后国际化使用的,例如项目内如果写了settext("hello"),则会提示此警告,如果不用国际化,则不须考虑此提示,否则必须使用Res string.xml 进行plachholder

1.2.4 表现力 Performance

重要指数:极其重要

Performance的扫描结果

OverDraw:Painting regions more than once
众所周知,Android APP里面最重要的优化方面之一就是UI绘制方面优化,避免嵌套层级过多,导致多次onDraw,浪费性能从而造成APP卡顿
Lint此条目即可帮我们扫描到哪些XML有OverDraw的可能性。
开发的同学务必注意此条,按照提示的内容逐一检查,必须使Overdraw提示消失。

Unused resource
检测无用资源,减小apk体积,便于渠道商推广

1.2.5 安全性 Security

重要指数:一般
主要是提示高版本SDK下,app的兼容性可能会出问题

1.2.6 可用性 Usability

重要指数:一般
主要是提示能不能被Google搜索到,跟一些统计用量,如果专注于国内开发可不用考虑这个

1.2.7 资源可用性 Android Resource Validation

资源可用性

重要指数:一般
主要检测XML文件是不是引用了无效资源,当然 一般如果不修改好 编译过不去,大家也会修改的。

个人建议如果时间比较赶,来不及做很多优化,其他暂时都可以放放,直接把Performance里面的建议执行完即可。Lint的局限性在于其只能检测是否Overdraw,而类似数据大量加载导致的卡顿则需各位同学自己注意,利用CPU Profile去检测。

另外此处是Google给出的减少过度绘制的方法 :
There are several strategies you can pursue to reduce or eliminate overdraw:

  • Removing unneeded backgrounds in layouts.(移除不需要的背景)
  • Flattening the view hierarchy.(布局扁平化,即少嵌套,多用LinearLayout,ConstraintLayout)
  • Reducing transparency.(减少透明,替换Windows自带背景,不要在Theme文件里设置WindowTransparent)

检测是否真的减少绘制:

启用开发者选项, 然后,执行以下操作:

  1. Settings 并点按 Developer Options
  2. 向下滚动到 Hardware accelerated rendering 部分,并选择 Debug GPU Overdraw
  3. Debug GPU overdraw 对话框中,选择 Show overdraw areas
    Android 按如下方法为界面元素设置颜色,以便确定过度绘制的次数:
  • 真彩色(也就是原色): 没有过度绘制

  • 蓝色

    蓝色: 过度绘制 1 次

  • 绿色

    绿色: 过度绘制 2 次

  • 粉色

粉色: 过度绘制 3 次

  • 红色

    红色: 过度绘制 4 次或更多

InspectCode的结果还有其他很多种,因此篇主要讲Android的优化,其他的结果是项目代码方面的问题就不研究了,有兴趣的读者可以自己深入研究。


其他问题

1.3 LayoutInspector 布局检查器

LayoutInspector 是另外一个检测布局的便利工具,可以检测出布局是否有嵌套,使用方式如下:

  • 连接手机,运行程序
  • 点击Tools->LayoutInspector->show all process
  • choose your app
    这样,LayoutInspector就连接上手机APP了,然后开始进行布局分析,选择一个对应的APP,就可以看到具体的信息,LayouInspector会自动将它保存为 .li 文件并打开。 如图中所示,布局检查器将显示以下内容:
    View Tree:视图在布局中的层次结构。
    Screenshot:带每个视图可视边界的设备屏幕截图。
    Properties Table:选定视图的布局属性。


    捕捉的快照

    如果布局包括重叠视图,则默认情况下,只有前面的视图可以在屏幕截图中点击。 要让后面的视图可以在屏幕截图中点击,请执行以下操作: 在 View Tree 中右键点击前面的视图,然后取消选中 Show in preview。 此操作不会让视图内容消失;仅会让屏幕截图中的可点击边界消失,以便您可以点击在它后面的视图。
    所有LayoutInspector捕捉的.li文件 都会保存在/project/captures/ 内一个单独的 .li 文件中。

这个工具主要是便于直接查看app的实际布局是否过度嵌套。

1.4 ProGuard - 压缩代码以及资源 让你的APP更小

ProGuard 众所周知 是开启混淆的利器,但是他还有另外一种作用,就是减轻APK的体积,去掉无用代码,让我们来看看Google官方对此的介绍

  • 通过 ProGuard 移除未使用的代码 - 为您的版本构建[启用代码压缩]以运行 ProGuard。启用压缩可确保您交付的 APK 不含有未使用的代码。代码压缩通过 ProGuard 提供,ProGuard 会检测和移除封装应用中未使用的类、字段、方法和属性,包括自带代码库中的未使用项。ProGuard 还可优化字节码,移除未使用的代码指令,以及用短名称混淆其余的类、字段和方法。混淆过的代码可令您的 APK 难以被逆向工程,这在应用使用等安全敏感性功能时特别有用。
    资源压缩 通过适用于 Gradle 的 Android 插件提供,该插件会移除封装应用中未使用的资源,包括代码库中未使用的资源。它可与代码压缩发挥协同效应,使得在移除未使用的代码后,任何不再被引用的资源也能安全地移除。
    本文介绍的功能依赖下列组件:
  • [SDK Tools] 25.0.10 或更高版本
  • [适用于 Gradle 的 Android 插件]2.0.0 或更高版本

启用代码压缩,直接在build.gradle文件内相应的构建类型中添加 minifyEnabled true

每次构建时 ProGuard 都会输出下列文件:

  • dump.txt
    说明 APK 中所有类文件的内部结构。
  • mapping.txt
    提供原始与混淆过的类、方法和字段名称之间的转换。
  • seeds.txt
    列出未进行混淆的类和成员。
  • usage.txt
    列出从 APK 移除的代码。
    这些文件保存在 <module-name>/build/outputs/mapping/release/ 中。

启用资源压缩,在 build.gradle 文件中将 shrinkResources 属性设置为 true

android {
    ...
    buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
}

排查资源压缩问题
Gradle 还会在 <module-name>/build/outputs/mapping/release/(ProGuard 输出文件所在的文件夹)中创建一个名为 resources.txt 的诊断文件。该文件包括诸如哪些资源引用了其他资源以及使用或移除了哪些资源等详情。

GPU Rendering 渲染解析图,可根据此图分析判断性能消耗在何处

分析图.png

总结:本文主要介绍了Android性能优化的工具,其重点在于让APP
更稳: Memory Profile 检测内存泄漏问题,内存优化问题
更快:CPU Profile 检测函数耗时过长
更省:Lint跟LayoutInspector 对应 检测布局重绘问题,减少无用资源问题
更小: Progurad 减少无用代码,压缩资源

1 Render UI

render-1.png

2 减轻CPU负载

CPU-1.png

CPU-2.png

3 内存处理思路

MEMORY-1.png

后续分析工具

tools-1.png

推荐阅读更多精彩内容