Android 性能优化工具及基本原理

227 阅读3分钟

1. 卡顿的原因

  1. 在主线程处理耗时任务,比如处理 IO,操作数据库,数据计算等。
  2. 在主线程进行网络请求,当然在 Android 4.0 后,在主线程进行网络请求会抛出异常。
  3. 解析 xml 布局或者 new 的视图层级过多。
  4. 调用系统硬件,比如相机。
  5. 加载图片没有处理好。
  6. 启动的线程过多,cpu 占用率过高

检测的方式:

  • 1. 使用工具 BlockCannary,带有图形界面,可以设置卡顿的阀值。

  • 2. 使用 Android 自带的工具类 StrictMode。

BlockCannary

它对主线程操作进行了完全透明的监控,并能输出有效的信息,帮助开发分析、定位到问题所在,迅速优化应用

  • 非侵入式,简单的两行就打开监控,不需要到处打点,破坏代码优雅性。
  • 精准,输出的信息可以帮助定位到问题所在 (精确到行),不需要像 Logcat 一样,慢慢去找。
    目前包括了核心监控输出文件,以及 UI 显示卡顿信息功能。

原理

Android 中主线程 ActivityThread 创建一个Looper (Looper.prepare),而 Looper 又会关联一个 MessageQueue,主线程 Looper会在应用的生命周期内不断轮询 (Looper.loop),从 MessageQueue 取出 Message 更新 UI 

如果消息是通过 Handler.post(runnable) 方式投递到 MQ 中的,那么就回调 runnable#run 方法; 

如果消息是通过 Handler.sendMessage() 的方式投递到 MQ 中,那么回调 handleMessage 方法; 

不管是哪种回调方式,回调一定发生在 UI 线程。因此如果应用发生卡顿,一定是在 dispatchMessage() 中执行了耗时操作。我们通过给主线程的 Looper 设置一个 Printer,打点统计 dispatchMessage() 方法执行的时间,如果超出阀值,表示发生卡顿,则dump 出各种信息,提供开发者分析性能瓶颈。

StrictMode

最常用的场景就是检测主线程中本地磁盘、网络读写等耗时的操作以及 Activity 泄露等

主要采用 ThreadPolicy (线程策略) 和 VmPolicy (Vm 策略)进行检测,各策略检测内容如下:

ThreadPolicy

线程策略检测的内容有:

  • 自定义的耗时调用使用 detectCustomSlowCalls() 开启。
  • 磁盘读取操作使用 detectDiskReads() 开启。
  • 磁盘写入操作使用 detectDiskWrites() 开启。
  • 网络操作使用 detectNetwork() 开启。

VmPolicy

虚拟机策略检测的内容有:

 1、Activity 泄露使用 detectActivityLeaks() 开启。 

2、未关闭的 closable 对象泄露使用 detectLeakedClosableObjects() 开启。 

3、泄露的 sqlite 对象使用 detectLeakedSqlLiteObjects() 开启。 

4、检测实例数量使用 setClassInstanceLimit() 开启。

  • 3.2 使用

    class DebugUtil { public static void startStrictModeVmPolicy() { StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectActivityLeaks()/检测Activity内存泄露/ .detectLeakedClosableObjects()/检测未关闭的Closable对象/ .detectLeakedSqlLiteObjects() /检测Sqlite对象是否关闭/ /也可以采用detectAll()来检测所有想检测的东西/ .penaltyLog().build()); } public static void startStrictModeThreadPolicy() { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads()/磁盘读取操作检测/ .detectDiskWrites()/检测磁盘写入操作/ .detectNetwork() /检测网络操作/ /也可以采用detectAll()来检测所有想检测的东西/ .penaltyLog().build()); }}

查看日志输出:

D/StrictMode( 9730): StrictMode policy violation; ~duration=20 ms: android.os.StrictModeStrictModeDiskReadViolation:policy=31violation=2D/StrictMode(9730):atandroid.os.StrictModeStrictModeDiskReadViolation: policy=31 violation=2 D/StrictMode( 9730): at android.os.StrictModeAndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1176) D/StrictMode( 9730): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:106) D/StrictMode( 9730): at libcore.io.IoBridge.open(IoBridge.java:390) D/StrictMode( 9730): at java.io.FileOutputStream.(FileOutputStream.java:88) D/StrictMode( 9730): at com.example.strictmodedemo.MainActivity.writeToExternalStorage(MainActivity.java:56) D/StrictMode( 9730): at com.example.strictmodedemo.MainActivity.onCreate(MainActivity.java:30) D/StrictMode( 9730): at android.app.Activity.performCreate(Activity.java:4543)