Android App 性能优化实践

1. 问题发现

在最近的一次 feature 开发中,我发现单个页面上 button pressed 的状态在手指移开后1s 左右才生效,整个过程像是镜头回放的慢动作一样。在查看了metrics tool 中对应 Activity 的性能指标后,我意识到应该是有比较严重的性能问题了:layout 耗费了2~3s的时间,同时出现严重的掉帧。

before_opt-crunch.png

2. 首次尝试

首先想到的方案是查看当前Activity的布局,通过adb shell dumpsys activity pkg-name 看到当前的 View Hierarchy 层级深度已经达到了14层。整个布局深度包括了系统的id 为 android:id/contentFrameLayout至Root View 的4层,以及第三方某自定义的6层布局。

重新调整layout文件:

  • 使用 标签对运行过程中动态 inflate 的View 布局进行优化
  • 将Activity的顶层 ViewGroup 设置为 ConstraintLayout,以便减少冗余的层级。

在调整完成后,再次开启监控模式中的GPU条形图发现性能有所提升,但是整体来看仍不明显。layout耗时以及掉帧的问题依旧存在。

3. Profile 瓶颈

完成2中的调整后,我发觉必须要能定位到瓶颈点才能从根本上解决这次的性能问题。对比官方文档 profile-gpu 中的GPU柱状图颜色的说明,可以初步判定问题极有可能出现在 AnimationMeasure 的节点上。

更进一步的,我开始了 profile CPU, 通过 record trace 在Sample(Java) 模式下发现了指定的间隔时间段调用最频繁的方法,measure 方法的频繁调用果然成为了整个的瓶颈部分:

Screen Shot 2018-12-04 at 23.43.15.png

切换到 Instrumented (Java) 模式后再次进行观察,发现调用最频繁的方法终于浮出水面:


Screen Shot 2018-12-04 at 11.33.42.png

4. 真相大白

原来是Video播放过程中,进度更新的回调方法里面,有个逻辑是通过 TextView#setText() 直接更新当前的播放时间戳 MM:SS 。而播放进度的刷新频率被设置成了 33ms. ( ⊙ o ⊙ )!

将刷新时间戳的逻辑改成秒级刷新后,UI表现终于恢复正常了:

after_opt-crunch.png

5. 后记

P.S.
2018.12.05 经过与一位同事的讨论发现,如果将显示播放的时间戳的 TextView 布局中的 layout_width 设置为固定的值(之前的设置是wrap_content!),则也可以完全避免这个问题。

你可能感兴趣的:(Android App 性能优化实践)