-StrictMode类是Android 2.3 (API 9)引入的一个工具类,可以用来帮助开发者发现代码中的一些不规范的问题。
提供了各种策略,比如监视网络访问 和 磁盘读写操作.当开发者违背了事先设定的规则的时候,就会通过不同的方法去提醒开发者改善代码.
这样的话,就可以帮助我们发现并定位问题,做到有的放矢,更快的解决问题.
官方文档:
developer.android.com/reference/android/os/StrictMode.html
翻译过来就是严格模式 的意思.
StrictMode的作用
在Android开发中,通常都会涉及到网络访问,数据库读写,磁盘读写操作.
在4.0之前,我们是可以在主线程(UI线程)来进行网络访问的,4.0之后,如果在主线程访问网络,那么系统就会给我们抛出一个异常(NetworkOnMainThreadException)
但是,像数据库操作和磁盘操作,等耗时任务则没有严格的限制,而这些则是很影响一款app性能和运行速度的
使用StrictMode.系统会检测出主线程中违例情况并做出反应,如日志打印,弹出对话框等.
我们通可以在 自定义的Application类或者Activity以及其他组件的onCreate()方法中启动 StrictMode,为了能够全局检测应用中的问题,建议放在Application中
public void onCreate() {
if (DEVELOPER_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyDialog() //弹出违规提示对话框
.penaltyLog() //在Logcat 中打印违规异常信息
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate();
}
ps:注意:
监控策略
严格模式主要检测两大问题,一个是线程策略,即TreadPolicy
,主要用于监测主线程中耗时操作.
另一个是VM策略,即VmPolicy
,主要用于发现内存问题
detectCustomSlowCalls()
.监测自定义的耗时操作
detectDiskReads()
.监测磁盘读取操作
detectDiskWrites()
.监测磁盘写入操作
detectNetwork()
.监测网络操作
permitCustomSlowCalls()
、permitDiskReads()
、permitDiskWrites()
、permitNetwork()
对应的用于关闭某一项的监测.
detectActivityLeaks()
用于监测Activity泄露
detectLeakedClosableObjects()
用于监测未关闭的Closable对象泄露
detectLeakedSqlLiteObjects()
用于监测泄露的Sqlite对象
setClassInstanceLimit()
用于检测实例数量
通知开发者
一般以penalty
开头的方法都是用做提示功能的.
penaltyDeath()
,当触发违规条件时,直接Crash掉当前应用程序。
penaltyDeathOnNetwork()
,当触发网络违规时,Crash掉当前应用程序。
penaltyDialog()
,触发违规时,显示对违规信息对话框。
penaltyFlashScreen()
,会造成屏幕闪烁,不过一般的设备可能没有这个功能。
penaltyDropBox()
,将违规信息记录到 dropbox 系统日志目录中(/data/system/dropbox)
如一下代码,运行后
/** * Created by BoBoMEe on 2015/12/29. */
public class StrictModeSample extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyDialog() //弹出违规提示对话框
.penaltyLog() //在Logcat 中打印违规异常信息
.build());
test();
}
private void test() {
URL url = null;
try {
url = new URL("http://php.weather.sina.com.cn/iframe/index/w_cl.php?code=js&day=0&city=&dfc=1&charset=utf-8");
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);
}
writeToFile(sb);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void writeToFile(StringBuffer sb) {
FileWriter fw = null;
try {
File externalStorage = Environment.getExternalStorageDirectory();
File destFile = new File(externalStorage, "dest.txt");
fw = new FileWriter(destFile);
fw.write(sb.toString());
fw.close();
} catch (IOException e) {
e.printStackTrace();
} /*finally { try { fw.close(); } catch (IOException e) { e.printStackTrace(); } }*/
}
}
运行上面的代码 ,会报出一下错误.
D/StrictMode: StrictMode policy violation; ~duration=2871 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=63 violation=2
at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1135)
同时,程序会弹出一个对话框.提示开发者来修改代码.通过log信息,我们可以知道是因为耗时的磁盘操作造成的
监测UI线程调用的那些方法执行得比较慢,需要和StrictMode.noteSlowCall
配合使用
private void test() {
StrictMode.noteSlowCall("test");
new Thread() {
@Override
public void run() {
}
}.start();
}
会得到类似的信息
D/StrictMode(1349): StrictMode policy violation; **~duration=2019 ms:
我们可以从信息中看到某个方法执行了多长时间,但是这个时间一般是要比实际值要高那么一点点的.
常见解决办法
private void test() {
new Thread() {
@Override
public void run() {
URL url = null;
try {
url = new URL("http://php.weather.sina.com.cn/iframe/index/w_cl.php?code=js&day=0&city=&dfc=1&charset=utf-8");
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);
}
// writeToFile(sb);
handler.sendEmptyMessage(001);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(StrictModeSample.this, "success", Toast.LENGTH_LONG).show();
}
};
当我们反复旋转屏幕,会得到类似下面的log信息
E/StrictMode(4784): class com.android.StrictModeSample ; instances=4; limit=1
这句话的意思是存在4个实例,而只允许一个,就是我们的Activity发生了泄露了,这时候,我们就要看一下代码了,在上面这段代码中handler持有外部类Activity的强应用,
StrictMode除了可以检测Activity的内存泄露之外,从API 11 开始,还能自定义检测类的实例泄露。
public StrictMode.VmPolicy.Builder setClassInstanceLimit (Class klass, int instanceLimit)
常见解决办法
unregisterReceiver(this.receiver);