-- 作者 谢恩铭 转载请注明出处
StrictMode简介
StrictMode (android.os.StrictMode) 是一个自Android 2.3版(API 9。Gingerbread,姜饼)引入的类。
StrictMode是Strict和Mode的合并,在英语中,strict表示“严格的”,mode表示“模式”,因此,StrictMode就是“严格的模式”,或叫“严苛模式”。
既然是严苛的,那么肯定是对什么东西有限制。因为严格的老师肯定不会对坏学生纵容的,对吧,所以可以想见StrictMode是用来监测Android中的什么东西。
是的,聪明如你果然猜对了。StrictMode就是用来指定一系列策略(policy),对相应规则(rule)进行检查并且做出反应。
这些策略大致包括Android的编码规范,例如监控在主线程(UI线程)中的操作,等等。
StrictMode有不同的策略,每种策略又用不同的规则(rule),每种规则又对应不同的方法,一旦规则被违反,这些对应的方法就会被用来做出反应。
注意 :
- 在Debug模式启用StrictMode,别在Release模式启用。用户的小心脏是很脆弱的,假如一点点违规就导致应用崩溃,或者弹窗,那用户会把你的应用删除了。
- 特别地, 调用JNI实现的磁盘读写操作和网络操作不会激活StrictMode。
策略类型
目前,有两种类型的策略:
- Thread Policy : 线程策略应用到特定的线程。
- VM Policy : VM是Virtual Machine的缩写,表示“虚拟机”,不要搞错以为是Virtual Memory(虚拟内存)。应用于虚拟机进程中的所有线程。
ThreadPolicy.Builder中的一些方法:
- detectAll() : 侦测一切潜在违规
- detectCustomSlowCalls() : 侦测自定义的耗时操作
- detectDiskReads() : 侦测磁盘读
- detectDiskWrites() : 侦测磁盘写
- detectNetwork() : 侦测网络操作
- permitAll() : 禁用所有侦测
- permitDiskReads() : 允许磁盘读
VmPolicy.Builder中的一些方法 :
- detectAll() : 侦测一切潜在违规
- detectActivityLeaks() : 侦测Activity(活动)泄露
- detectLeakedClosableObjects() : 当显式中止方法调用之后,假如可被Closeable类或其他的对象没有被关闭。
处罚
Penalty是英语“处罚”的意思,所以凡是以penalty开头的方法都表示违规时要做出什么反应。
对于每个策略,我们可以指定多个处罚形式,而处罚也是从最不严重的到最严重(从打印日志到直接crash(崩溃))依次执行。
暂时还没有机制能使监测到的违规与特定的处罚对应。
- penaltyDeath() : 违规时,直接使应用崩溃。
- penaltyDialog() : 违规时,向开发者显示一个恼人的Dialog对话框。
- penaltyLog() : 违规时,将违规信息写入系统日志。
使用
StrictMode使用起来非常简单。
设置策略
你可以在你的Application(应用)或者应用中的Activity的onCreate()方法中设置启用StrictMode的策略。不过为了更全面的监测,最好就放在Application的onCreate()方法中,一劳永逸。
设置StrictMode可以通过setVmPolicy(StrictMode.VmPolicy)或setThreadPolicy(StrictMode.ThreadPolicy)。
setVmPolicy(StrictMode.VmPolicy)或setThreadPolicy(StrictMode.ThreadPolicy)方法的参数是用VmPolicy.Builder或ThreadPolicy.Builder来构建的。
举例:
@Override
public void onCreate() {
super.onCreate();
// 分别为MainThread和VM设置Strict Mode
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.detectResourceMismatches()
.detectCustomSlowCalls()
.penaltyDeath()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.detectActivityLeaks()
.penaltyDeath()
.build());
}
}
扩充StrictMode
1.用getThreadPolicy() 或getVmPolicy()获得当前策略。
2.用setThreadPolicy() or setVmPolicy()来扩充它。
举例:
StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(oldThreadPolicy)
.permitDiskWrites() // 在原有策略的规则基础上,不监测读写磁盘
.build());
StrictMode.VmPolicy oldVmPolicy = StrictMode.getVmPolicy();
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder(oldVmPolicy)
.detectFileUriExposure() // 在原有策略的规则基础上,监测文件URI暴露
.build());
StrictMode的日志形式
09-04 16:15:34.592: DEBUG/StrictMode(15883): StrictMode policy violation; ~duration=319 ms: android.os.StrictMode$StrictModeDiskWriteViolation: policy=31 violation=1
09-04 16:15:34.592: DEBUG/StrictMode(15883): at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk(StrictMode.java:1041)
可以看到,在Logcat中总会有StrictMode开头的Log。因此,我们可以这样查找所有StrictMode的日志:
adb logcat | grep StrictMode
测试实例
写入外部存储
public void writeToExternalStorage() {
File externalStorage = Environment.getExternalStorageDirectory();
File destFile = new File(externalStorage, "dest.txt");
try {
OutputStream output = new FileOutputStream(destFile, true);
output.write("coderunity.com".getBytes());
output.flush();
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Activity泄露
下面的代码,如果我们进入、退出多次LeakyActivity, 则会触发
StrictMode.ThreadPolicy.Builder().detectActivityLeaks() :
public class MyApplication extends Application {
public static final boolean IS_DEBUG = true;
public static ArrayList sLeakyActivities = new ArrayList();
}
public class LeakyActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.sLeakyActivities.add(this);
}
}
在设置中启用StrictMode
我们也可以在Android设备的设置(Settings)中启用StrictMode:
Settings(设置) -> Developer options(开发者选项),然后开启它。开启之后,一旦应用在主线程中执行耗时操作,屏幕就会闪烁。
人世间,
万千情感皆有温度,
千万代码似有性格。
这里有原创教程,IT丛林......
和你一起探索程序人生。
我是谢恩铭,在巴黎奋斗的嵌入式软件工程师。
个人简介
热爱生活,喜欢游泳,略懂烹饪。
人生格言:“向着标杆直跑”