转载自:https://blog.csdn.net/weixin_40763897/article/details/89018306

性能无外乎就是CPU密集型或I/O密集型两种。
StrictMode是一个开发者工具,常用于捕获在应用主线程中发生的磁盘I/O、网络访问违例等问题。

StrictMode具体能检测什么呢

StrictMode主要检测两大问题:线程策略(TreadPolicy)和VM策略(VmPolicy)。

ThreadPolicy线程策略:

1.自定义的耗时调用,使用detectCustomSlowCalls()开启;
2.磁盘读取操作,使用detectDiskReads()开启;
3.磁盘写入操作,使用detectDiskWrites()开启;
4.网络操作,使用detectNetwork()开启。

VmPolicy虚拟机策略:

1.Activity泄漏,使用detectActivityLeaks()开启;
2.未关闭的Closable对象泄漏,使用detectLeakedClosableObjects()开启;
3.泄漏的Sqlite对象,使用detectLeakedSqlLiteObjects()开启;
4.检测实例数量,使用setClassInstanceLimit()开启。

如何使用呢?

可以在应用的Application、Activity或者其他应用组件的onCreate方法中加入检测代码,如:

  public void onCreate() {if (DEVELOPER_MODE) {StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork()   // or .detectAll() for all detectable problems.penaltyLog().build());StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());}super.onCreate();}

如果观测结果呢?

StrictMode有多种报告违例的形式,但要分析具体违例情况,还是需要查看日志。我们在此介绍两种方式,一种是在android studio IDE的logcat里查看:

另一种是在终端下,过滤StrictMode得到违例的具体stacktrace信息(手机要打开调试用的app),然后打开命令终端,使用adb命令来查看:

~$ adb logcat | grep StrictMode

如果发现有违例的行为,可以通过使用线程(threads)、Handler、AsyncTask、IntentService等帮助解决。提供一下些常用的措施:

  • 假如在主线程中进行文件读写出现了违例,可用工作线程(另外开辟子线程)来解决,必要时还可以结合Handler一起来解决。
  • SharedPreferences的写入操作,在API 9以上应该优先使用apply而非commit。
  • 如果是存在未关闭的Closable对象(如有些流OutputStream,在出现异常时,未来得及关闭),根据对应的stacktrace进行关闭。
  • 如果是SQLite对象泄漏,根据对应的stacktrace进行释放。

例子

接下来我们来举个在主线程中的文件写入,引起违例警告的例子:

1.首先Activity的onCreate方法中加上检测代码:
注:以下的代码启用全部的ThreadPolicy和VmPolicy违例检测


StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());

2.这是引起违例的代码:

    public void writeToExternalStorageInMainThread() {File externalStorage = Environment.getExternalStorageDirectory();File destFile = new File(externalStorage, "hello.txt");try {OutputStream output = new FileOutputStream(destFile, true);output.write("I am testing io".getBytes());output.flush();output.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}

3.运行app,观察logcat的输出,下面是部分截图:

logcat已告诉我们出现了违例和出现的位置。

4.解决这个违例
修改一下writeToExternalStorageInMainThread方法,将引起违例的代码都放在一个工作线程中去执行,如下所示:

    public void writeToExternalStorageInMainThread() {new Thread(new Runnable() {@Overridepublic void run() {File externalStorage = Environment.getExternalStorageDirectory();File destFile = new File(externalStorage, "hello.txt");OutputStream output = null;try {output = new FileOutputStream(destFile, true);output.write("I am testing io".getBytes());output.flush();output.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {if(output != null){try {output.close();} catch (IOException e) {e.printStackTrace();}}}}}).start();}

demo示例

检测内存泄漏

通常情况下,检测内存泄漏,我们会使用MAT(Eclipse Memory Analyzer)工具对heap dump 文件进行分析。但是使用StrictMode,只需要过滤日志就能发现内存泄漏,更快捷方便。

1.首先,需要开启对检测Activity泄漏的违例检测,可以使用detectAll或者detectActivityLeaks():

StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectActivityLeaks().penaltyLog().build());

2.写一段能够产生Activity泄漏的代码

public class LeakActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_leak);if(MyApplication.IS_DEBUG){MyApplication.sLeakyActivities.add(this);}}
}

3.MyApplication中关于sLeakyActivities的部分实现

public class MyApplication extends Application {public static final boolean IS_DEBUG = true;public static ArrayList<Activity> sLeakyActivities = new ArrayList<Activity>();@Overridepublic void onCreate() {StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectActivityLeaks().penaltyLog().build());super.onCreate();}
}

4.引发内存泄漏的操作:
通过不断从MainActivity打开LeakActivity,再返回,再打开,如此反复操作,引发内存泄漏,下面是MainActivity的代码:


public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextView textView = (TextView)findViewById(R.id.tv);textView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startActivity(new Intent(MainActivity.this,LeakActivity.class));}});}
}

5.当我们反复进入LeakyActivity再退出,在Logcat中过滤StrictMode就会得到这样的日志:

2019-04-04 19:49:43.502 32708-32708/com.wong.appmemoryleakydemo E/StrictMode: class com.wong.appmemoryleakydemo.LeakActivity; instances=7; limit=1android.os.StrictMode$InstanceCountViolation: class com.wong.appmemoryleakydemo.LeakActivity; instances=7; limit=1at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

分析日志:LeakyActivity本应该只存在一个实例的,但现在存在了7个,说明LeakyActivity发生了内存泄漏。

检测内存泄漏demo

自定义检测类的实例泄漏

我们还可以通过StrictMode自定义检测类的实例泄漏。从API 11 开始,系统提供的这个方法setClassInstanceLimit可以实现我们的需求。比如说有个类叫SingleAction.class,我们认为在运行时,它应该只有一个实例,如果多一个,我们就可以认为发生了内存泄漏:
1.开启违例检测,如下:

StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().setClassInstanceLimit(SingleAction.class,1).penaltyLog().build());

上面代码就是说,当SingleAction类出现多于一个实例时,就报告内存泄漏。

耗时调用违例:noteSlowCall
StrictMode从API 11开始允许开发者自定义一些耗时调用违例,这种自定义适用于自定义的任务执行类中,比如自定义任务处理类MyTaskExecutor:

public class MyTaskExecutor {public void execute(Runnable task){task.run();}
}

但是如果我们想跟踪每个任务执行的耗时情况,如果耗时大于500毫秒就通知我们,我们该怎么办呢?StrictMode的noteSlowCall方法可以实现这个功能,修改MyTaskExecutor,如下所示:

public class MyTaskExecutor {public static long CAN_BEAR_TIME = 500;public void execute(Runnable task){long sTime = SystemClock.uptimeMillis();task.run();long cTime = SystemClock.uptimeMillis() - sTime;if(cTime > CAN_BEAR_TIME){StrictMode.noteSlowCall("slow call cost:"+cTime);}}

执行一个耗时1000毫秒的任务,测试一下:

package com.wong.timeconsumingviolation;import android.os.StrictMode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyTaskExecutor taskExecutor = new MyTaskExecutor();taskExecutor.execute(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});}
}

在Logcat中过滤StrictMode就会得到这样的日志:

2019-04-04 20:27:27.020 6147-6147/com.wong.timeconsumingviolation D/StrictMode: StrictMode policy violation; ~duration=29 ms: android.os.StrictMode$StrictModeCustomViolation: policy=65599 violation=8 msg=slow call cost:1001at android.os.StrictMode$AndroidBlockGuardPolicy.onCustomSlowCall(StrictMode.java:1397)at android.os.StrictMode.noteSlowCall(StrictMode.java:2340)at com.wong.timeconsumingviolation.MyTaskExecutor.execute(MyTaskExecutor.java:19)at com.wong.timeconsumingviolation.MainActivity.onCreate(MainActivity.java:17)at android.app.Activity.performCreate(Activity.java:7040)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2809)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2931)at android.app.ActivityThread.-wrap11(Unknown Source:0)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1620)at android.os.Handler.dispatchMessage(Handler.java:105)at android.os.Looper.loop(Looper.java:173)at android.app.ActivityThread.main(ActivityThread.java:6698)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)

从日志分析来看,我们已成功跟踪到耗时超过500ms的任务了。
注意上面的日志结果中的:duration=29 ms,并非耗时任务的执行时间,而我们自定义信息msg=slow call cost:1001包包含的时间才是真正的耗时。

自定义耗时违例demo

注意

  1. StrictMode无法监控JNI中的磁盘IO和网络请求。
  2. 应用中并非需要解决全部的违例情况,比如有些IO操作必须在主线程中进行。
  3. 通常情况下StrictMode给出的耗时相对实际情况偏高,并不是真正的耗时数据。

Android性能调优--StrictMode相关推荐

  1. Android性能调优篇之探索垃圾回收机制

    开篇废话 如果我们想要进行内存优化的工作,还是需要了解一下,但这一块的知识属于纯理论的,有可能看起来会有点枯燥,我尽量把这一篇的内容按照一定的逻辑来走一遍.首先,我们为什么要学习垃圾回收的机制,我大概 ...

  2. android性能调优的工具,神兵利器-Android 性能调优工具 Hugo

    在进行Android性能调优.减少应用卡顿时,寻找可优化的code是一个必要的过程.如何发现应用中的耗时任务甚至是耗时函数呢,如果可以在log中打印每个方法的执行时间,甚至把执行方法时的输入输出同时打 ...

  3. Android性能调优实例

    本文主要分享自己在appstore项目中的性能调优点,包括 同步改异步.缓存.Layout优化.数据库优化.算法优化.延迟执行等. 一.性能瓶颈点 整个页面主要由6个Page的ViewPager,每个 ...

  4. StrictMode ——Android性能调优的利器

    性能无外乎就是CPU密集型或I/O密集型两种. StrictMode是一个开发者工具,常用于捕获在应用主线程中发生的磁盘I/O.网络访问违例等问题. StrictMode具体能检测什么呢 Strict ...

  5. Android性能调优利器StrictMode

    2019独角兽企业重金招聘Python工程师标准>>> 作为Android开发,日常的开发工作中或多或少要接触到性能问题,比如我的Android程序运行缓慢卡顿,并且常常出现ANR对 ...

  6. Android性能调优篇之探索JVM内存分配

    开篇废话 今天我们一起来学习JVM的内存分配,主要目的是为我们Android内存优化打下基础. 一直在想以什么样的方式来呈现这个知识点才能让我们易于理解,最终决定使用方法为:图解+源代码分析. 欢迎访 ...

  7. Android性能调优:App启动速度优化

    一.App启动分类 1.冷启动 Cold start 在启动应用前,系统还没有App的任何进程.比如设备开机后应用的第一次启动,系统杀掉应用进程 (如:系统内存吃紧引发的 kill 和 用户主动产生的 ...

  8. android性能调优!2021年Android春招面试经历,再不刷题就晚了!

    前言 对于字节跳动的二面三面而言,Framework+MVP架构+HashMap原理+性能优化+Flutter+源码分析等问题都成高频问点!然而很多的朋友在面试时却答不上或者答不全!今天在这分享下这些 ...

  9. 深入浅出Android性能调优,震撼来袭免费下载!

    前言 成为一名优秀的Android开发,需要一份完备的知识体系,在这里,让我们一起成长为自己所想的那样. 本文思维导图 1. 简历篇 如果把自己看成一个产品,那么简历就是说明书. 写简历看似简单,想写 ...

最新文章

  1. python numpy矩阵索引_python-为什么scipy csr矩阵的行索引比numpy数组...
  2. 如何去除Windows8测试版界面“水印”
  3. pytorch实现LeNet5
  4. linux登录用户目录,linux命令
  5. LintCode 4.丑数
  6. 软件测试之“支付功能”测试
  7. VB text控件如何实现换行
  8. FlexBuilder3安装集成eclipse
  9. 【点宽专栏】Dual Thrust 交易策略
  10. 用Java实现24点游戏
  11. 制作Windows severs 2019启动盘
  12. python中的Pickle文件和npy文件
  13. nmn产品品牌,nmn产品哪家更靠谱,看完不花冤枉钱
  14. MTK-EIS电子防抖-gyro校准
  15. linux硬盘对拷 再生龙,使用Clonezilla(再生龙)克隆Linux系统
  16. 攻防世界_moile
  17. django--安装
  18. 项目构建工具--webpack
  19. 学PS平面设计前,你需要先了解这些
  20. 内网渗透:八、CVE-2020-1472 NetLogon 域内提权漏洞(域控密码置空)

热门文章

  1. 200 : parsererror错误
  2. 组图:男生搭25辆顺风车行程3700公里回家
  3. 绕线的影响?SI来告诉你
  4. springboot导出pdf到前端浏览器预览下载
  5. 计算机网络:局域网协议
  6. HQChart实战教程46-十字光标右侧按钮点击增加刻度线
  7. C# treeview滚动条事件
  8. Java设计模式之从[魔兽世界副本]分析原型(Prototype)模式
  9. 我想请问一下逆战开透视怎么加密呀?
  10. HIVE视图VIEW