StrictMode类是Android 2.3 (API 9)引入的一个工具类,可以用来帮助开发者发现代码中的一些不规范的问题,以达到提升应用响应能力的目的。举个例子来说,如果开发者在UI线程中进行了网络操作或者文件系统的操作,而这些缓慢的操作会严重影响应用的响应能力,甚至出现ANR对话框。为了在开发中发现这些容易忽略的问题,我们使用StrictMode,系统检测出主线程违例的情况并做出相应的反应,最终帮助开发者优化和改善代码逻辑。

StrictMode具体能检测什么

严苛模式主要检测两大问题,一个是线程策略,即TreadPolicy,另一个是VM策略,即VmPolicy。

ThreadPolicy线程策略检测

线程策略检测的内容有

自定义的耗时调用 使用detectCustomSlowCalls()开启

磁盘读取操作 使用detectDiskReads()开启

磁盘写入操作 使用detectDiskWrites()开启

网络操作 使用detectNetwork()开启

VmPolicy虚拟机策略检测

Activity泄露 使用detectActivityLeaks()开启

未关闭的Closable对象泄露 使用detectLeakedClosableObjects()开启

泄露的Sqlite对象 使用detectLeakedSqlLiteObjects()开启

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

工作原理

其实StrictMode实现原理也比较简单,以IO操作为例,主要是通过在open,read,write,close时进行监控。libcore.io.BlockGuardOs文件就是监控的地方。以open为例,如下进行监控。

@Override

public FileDescriptor open(String path, int flags, int mode) throws ErrnoException {

BlockGuard.getThreadPolicy().onReadFromDisk();

if ((mode & O_ACCMODE) != O_RDONLY) {

BlockGuard.getThreadPolicy().onWriteToDisk();

}

return os.open(path, flags, mode);

}

其中onReadFromDisk()方法的实现,代码位于StrictMode.java中。

public void onReadFromDisk() {

if ((mPolicyMask & DETECT_DISK_READ) == 0) {

return;

}

if (tooManyViolationsThisLoop()) {

return;

}

BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);

e.fillInStackTrace();

startHandlingViolationException(e);

}

常见用法

严格模式的开启可以放在Application或者Activity以及其他组件的onCreate方法。为了更好地分析应用中的问题,建议放在Application的onCreate方法中。

其中,我们只需要在app的开发版本下使用 StrictMode,线上版本避免使用 StrictMode,这里定义了一个布尔值变量DEV_MODE来进行控制。

private boolean DEV_MODE = true;

public void onCreate() {

if (DEV_MODE) {

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()

.detectCustomSlowCalls() //API等级11,使用StrictMode.noteSlowCode

.detectDiskReads()

.detectDiskWrites()

.detectNetwork() // or .detectAll() for all detectable problems

.penaltyDialog() //弹出违规提示对话框

.penaltyLog() //在Logcat 中打印违规异常信息

.penaltyFlashScreen() //API等级11

.build());

StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()

.detectLeakedSqlLiteObjects()

.detectLeakedClosableObjects() //API等级11

.penaltyLog()

.penaltyDeath()

.build());

}

super.onCreate();

}

其中Android3.0引入的方法包括detectCustomSlowCalls()和noteSlowCode(),它们都是用来检测应用中执行缓慢代码的或者潜在的缓慢代码。

查看报告结果

严格模式有很多种报告违例的形式,但是想要分析具体违例情况,还是需要查看日志,终端下过滤StrictMode就能得到违例的具体stacktrace信息。

adb logcat | grep StrictMode

当然也可以选择弹窗形式来简明提醒开发者

弹窗警告

ThreadPolicy 详解

StrictMode.ThreadPolicy.Builder 主要方法如下

detectNetwork() 用于检查UI线程中是否有网络请求操作

检测UI线程中网络请求案例:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

Button btnTest;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()

.detectNetwork()

.penaltyLog()

.build());

btnTest = (Button) findViewById(R.id.btn_test);

btnTest.setOnClickListener(this);

}

@Override

public void onClick(View v) {

int id = v.getId();

switch (id) {

case R.id.btn_test:

postNetwork();

break;

}

}

/**

* 网络连接的操作

*/

private void postNetwork() {

try {

URL url = new URL("http://www.wooyun.org");

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.connect();

BufferedReader reader = new BufferedReader(new InputStreamReader(

conn.getInputStream()));

String lines = null;

StringBuffer sb = new StringBuffer();

while ((lines = reader.readLine()) != null) {

sb.append(lines);

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

运行后,触发的警告如下

detectDiskReads() 和 detectDiskWrites() 是磁盘读写检查

磁盘读写检查案例:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

Button btnTest;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()

.detectDiskWrites()

.detectDiskReads()

.penaltyLog()

.build());

btnTest = (Button) findViewById(R.id.btn_test);

btnTest.setOnClickListener(this);

}

@Override

public void onClick(View v) {

int id = v.getId();

switch (id) {

case R.id.btn_test:

writeToExternalStorage();

break;

}

}

/**

* 文件系统的操作

*/

public void writeToExternalStorage() {

File externalStorage = Environment.getExternalStorageDirectory();

File mbFile = new File(externalStorage, "castiel.txt");

try {

OutputStream output = new FileOutputStream(mbFile, true);

output.write("www.wooyun.org".getBytes());

output.flush();

output.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

}

运行后,触发的警告如下

noteSlowCall针对执行比较耗时的检查

StrictMode从 API 11开始允许开发者自定义一些耗时调用违例,这种自定义适用于自定义的任务执行类中,比如我们有一个进行任务处理的类,为TaskExecutor。

public class TaskExecutor {

public void execute(Runnable task) {

task.run();

}

}

先需要跟踪每个任务的耗时情况,如果大于500毫秒需要提示给开发者,noteSlowCall就可以实现这个功能,如下修改代码

public class TaskExecutor {

private static long SLOW_CALL_THRESHOLD = 500;

public void executeTask(Runnable task) {

long startTime = SystemClock.uptimeMillis();

task.run();

long cost = SystemClock.uptimeMillis() - startTime;

if (cost > SLOW_CALL_THRESHOLD) {

StrictMode.noteSlowCall("slowCall cost=" + cost);

}

}

}

执行一个耗时2000毫秒的任务

TaskExecutor executor = new TaskExecutor();

executor.executeTask(new Runnable() {

@Override

public void run() {

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

得到的违例日志,注意其中~duration=20 ms并非耗时任务的执行时间,而我们的自定义信息msg=slowCall cost=2000才包含了真正的耗时。

penaltyDeath(),当触发违规条件时,直接Crash掉当前应用程序。

penaltyDeathOnNetwork(),当触发网络违规时,Crash掉当前应用程序。

penaltyDialog(),触发违规时,显示对违规信息对话框。

penaltyFlashScreen(),会造成屏幕闪烁,不过一般的设备可能没有这个功能。

penaltyDropBox(),将违规信息记录到 dropbox 系统日志目录中(/data/system/dropbox),你可以通过如下命令进行插件:

adb shell dumpsys dropbox dataappstrictmode --print

permitCustomSlowCalls()、permitDiskReads ()、permitDiskWrites()、permitNetwork: 如果你想关闭某一项检测,可以使用对应的permit*方法。

VMPolicy 详解

StrictMode.VmPolicy.Builder 主要方法如下

detectActivityLeaks() 用户检查 Activity 的内存泄露情况

内存泄露检查案例:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()

.detectActivityLeaks()

.penaltyLog()

.build()

);

new Thread() {

@Override

public void run() {

while (true) {

SystemClock.sleep(1000);

}

}

}.start();

}

}

我们反复旋转屏幕就会输出提示信息(重点在 instances=2; limit=1 这一行)

这时因为,我们在Activity中创建了一个Thread匿名内部类,而匿名内部类隐式持有外部类的引用。而每次旋转屏幕是,Android会新创建一个Activity,而原来的Activity实例又被我们启动的匿名内部类线程持有,所以不会释放,从日志上看,当先系统中该Activty有4个实例,而限制是只能创建1各实例。我们不断翻转屏幕,instances 的个数还会持续增加。

detectLeakedClosableObjects()用于资源没有正确关闭时提醒

// 资源引用没有关闭检查案例

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()

.detectLeakedClosableObjects()

.penaltyLog()

.build()

);

File newxmlfile = new File(Environment.getExternalStorageDirectory(), "castiel.txt");

try {

newxmlfile.createNewFile();

FileWriter fw = new FileWriter(newxmlfile);

fw.write("猴子搬来的救兵WooYun");

//fw.close(); 我们在这里特意没有关闭 fw

} catch (IOException e) {

e.printStackTrace();

}

}

}

运行后触发警告如下

detectLeakedSqlLiteObjects() 和

detectLeakedClosableObjects()的用法类似,只不过是用来检查 SQLiteCursor 或者 其他 SQLite

对象是否被正确关闭

detectLeakedRegistrationObjects() 用来检查 BroadcastReceiver 或者

ServiceConnection 注册类对象是否被正确释放

setClassInstanceLimit(),设置某个类的同时处于内存中的实例上限,可以协助检查内存泄露

检测内存泄露案例

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private static class CastielClass{}

private static List classList;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

classList = new ArrayList();

StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()

.setClassInstanceLimit(CastielClass.class, 2)

.penaltyLog()

.build());

classList.add(new CastielClass());

classList.add(new CastielClass());

classList.add(new CastielClass());

classList.add(new CastielClass());

classList.add(new CastielClass());

classList.add(new CastielClass());

classList.add(new CastielClass());

classList.add(new CastielClass());

}

}

运行后触发警告如下

其他操作

除了通过日志查看之外,我们也可以在开发者选项中开启严格模式,开启之后,如果主线程中有执行时间长的操作,屏幕则会闪烁,这是一个更加直接的方法。

注意事项

只在开发阶段启用StrictMode,发布应用或者release版本一定要禁用它。

严格模式无法监控JNI中的磁盘IO和网络请求。

应用中并非需要解决全部的违例情况,比如有些IO操作必须在主线程中进行。

总结

以上所述是小编给大家介绍的Android严苛模式StrictMode使用详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

android strictmode有什么作用,Android严苛模式StrictMode使用详解相关推荐

  1. Android严苛模式StrictMode使用与取消

    StrictMode最常用来捕捉应用程序的主线程,报告与线程及虚拟机相关的策略违例.一旦检测到策略违例(policy violation),开发者将获得输出警告:包含了一个栈trace显示你的应用在何 ...

  2. android 严苛模式,Android严苛模式StrictMode使用详解

    StrictMode类是Android 2.3 (API 9)引入的一个工具类,可以用来帮助开发者发现代码中的一些不规范的问题,以达到提升应用响应能力的目的.举个例子来说,如果开发者在UI线程中进行了 ...

  3. android strictmode有什么作用,Android StrictMode运行流程(推荐)

    什么是 StrictMode(严苛模式) strictmode是android在 API9后引入的检测影响app运行流畅性的一种机制,例如我们都知道的主线程中不允许有网络操作这条规则就是严苛模式规则的 ...

  4. android mvp模式例子_Android中mvp模式使用实例详解

    MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示.作为一种新的模式,MVP与MVC有着一 ...

  5. Android基础入门教程——2.3.1 TextView(文本框)详解

    Android基础入门教程--2.3.1 TextView(文本框)详解 标签(空格分隔): Android基础入门教程 本节引言: 学习完Android中的六大布局,从本节开始我们来一个个讲解And ...

  6. Android studio 多渠道(多环境)打包grade配置详解

    Android studio 多渠道(多环境)打包grade配置详解 场景:开发app,我们需要两套环境或者两套环境以上的apk,每套环境的apk分两个版本debug版和release版. 公司有套平 ...

  7. android自定义圆角进度条,Android自定义进度条的圆角横向进度条实例详解

    1.本文将向你介绍自定义进度条的写法,比较简单,但还是有些知识点是需要注意的: invalidate()方法 RectF方法的应用 onMeasure方法的应用 2.原理 画3层圆角矩形,底层为黑色, ...

  8. Android四大组件之——Activity的生命周期(图文详解)

        转载请在文章开头处注明本博客网址:http://www.cnblogs.com/JohnTsai       联系方式:JohnTsai.Work@gmail.com       [Andro ...

  9. android相册和拍照并裁剪图片大小,Android 拍照并对照片进行裁剪和压缩实例详解...

    Android 拍照并对照片进行裁剪和压缩实例详解 本文主要介绍 Android 调用摄像头拍照并对照片进行裁剪和压缩,文中给出了主要步骤和关键代码. 调用摄像头拍照,对拍摄照片进行裁剪,代码如下. ...

最新文章

  1. Spark源码阅读02-Spark核心原理之作业执行原理
  2. 51CTO学院双十一营收400万,预测IT职业教育市场增长150%
  3. QQ空间Python爬虫v2.0--点赞数据分析
  4. 转:如何调用另一个python文件中的代码
  5. 人月神话阅读笔记(二)
  6. python实验二报告_20172304 2019-2020-2 《Python程序设计》实验二报告
  7. 年夜饭之 -- 洋葱炒墨鱼仔
  8. Django中的admin
  9. 男性护肤不“美白” 控油:男女有别 - 生活至上,美容至尚!
  10. 【麒麟操作系统】查看和关闭139、445端口的方法
  11. matlab系统解列模块,基于MATLAB的电力系统仿真终稿.doc
  12. 最全汇总GAN网络及其各种变体(附论文及代码实现)
  13. Manjaro Gnome Hidpi 缩放问题
  14. 推荐系统三十六式:矩阵分解 总结
  15. 我们所知道的压电材料参数及压电方程式ZJ-3型压电测试仪
  16. Android Verified Boot 2.0简要
  17. 四足机器人(从PCB到3D打印)
  18. hexo(next)——每日一言、今日诗词
  19. xilinx-vipp驱动分析
  20. SIM7600透传模式

热门文章

  1. vue父组件如何调用子组件里面的方法
  2. PE值、PB值、ROE和DCF值分别代表什么意思
  3. 我的世界服务器显示标指令,我的世界服务器指令|我的世界服务器指令大全
  4. SQLServer 随机生成指定范围的日期
  5. 解析XML报文--------DOM、JDOM、SAX
  6. 一次动态闪屏项目中用到的7个AE实用技巧
  7. 身为菜鸟的我写了一个日历查询程序
  8. 关于计算机的进制之间的转换 二进制转换十进制 十进制转换二进制
  9. 批处理之家 --专注于批处理 http://www.bathome.net/
  10. 网狐框架移植到linux,Red Hat反驳Linux漏洞报告 应关注危急缺陷!