StrictMode类是Android 2.3 (API 9)推出的一个工具类,可以用来帮助开发者发现代码中的一些非标准问题,从而提高应用的响应性。
StrictMode类是Android 2.3 (API 9)推出的一个工具类,可以用来帮助开发者发现代码中的一些非标准问题,从而提高应用的响应性。比如开发者在UI线程中操作网络或文件系统,这些缓慢的操作会严重影响应用的响应速度,甚至会出现ANR对话框。为了在开发中发现这些容易被忽略的问题,我们使用StrictMode,系统检测主线程的违规行为并做出相应的响应,最终帮助开发人员优化和改进代码逻辑。
官网:3358 developer . Android . com/reference/Android/OS/strict mode . html
StrictMode具体能检测什么
严格模式主要检测两大问题,一是线程策略,即TreadPolicy,二是VmPolicy,即VM策略。
ThreadPolicy线程策略检测
线程策略检测的内容包括
的自定义耗时调用是通过detectCustomSlowCalls()启动的
使用detectDiskReads()启动磁盘读取操作。
磁盘写操作是用detectDiskWrites()启动的
网络操作由detectNetwork()启动。
VmPolicy虚拟机策略检测
使用detectActivityLeaks()打开活动泄漏。
未关闭的可关闭对象泄漏通过使用detectLeakedClosableObjects()打开
泄漏的Sqlite对象是用detectLeakedSqlLiteObjects()打开的
检测实例的数量由setClassInstanceLimit()决定
工作原理
其实StrictMode的实现原理比较简单。以IO操作为例,主要是在打开、读取、写入和关闭过程中被监控。文件libcore.io.BlockGuardOs是监控的地方。以open为例,监控如下。
@覆盖
公共FileDescriptor open(String path,int flags,int mode)引发ErrnoException {
BlockGuard.getThreadPolicy()。onReadFromDisk();
if ((mode O_ACCMODE)!=O _ r only){
BlockGuard.getThreadPolicy()。onWriteToDisk();
}
返回os.open(路径、标志、模式);
}
实现了onReadFromDisk()方法,代码位于StrictMode.java。
public void onReadFromDisk() {
if((mPolicyMask DETECT _ DISK _ READ)==0){
返回;
}
if(toomanviolationthisloop()){
返回;
}
街区守卫。BlockGuardPolicyException e=new StrictModeDiskReadViolation(mPolicyMask);
e . fillinstacktrace();
startHandlingViolationException(e);
}
常见用法
严格模式开放可以放在应用程序或活动的onCreate方法和其他组件中。为了更好的分析应用中的问题,建议放在应用的onCreate方法中。
其中,我们只需要在app的开发版中使用StrictMode,避免在网络版中使用StrictMode。这里定义了一个布尔变量DEV_MODE来控制。
私有布尔DEV _ MODE=true
public void onCreate() {
if(开发模式){
StrictMode.setThreadPolicy(新StrictMode。ThreadPolicy.Builder()。detectCustomSlowCalls() //API级别11,使用StrictMode.noteSlowCode。detectDiskReads()。detectDiskWrites()。detectNetwork() //或。detectAll()用于所有可检测的问题。penaltyDialog() //弹出违规提示对话框。penaltyLog() //在Logcat中打印违规异常信息。penaltyFlashScreen() //API级别11。build());
StrictMode.setVmPolicy(新StrictMode。VmPolicy.Builder()。detectLeakedSqlLiteObjects()。detectleakedclosableobjects()//API级别11。penaltyLog()。penaltyDeath()。build());
}
super . oncreate();
}
其中,Android3.0引入的方法有detectCustomSlowCalls()和noteSlowCode(),这两种方法都是用来检测应用中的慢代码或潜在的慢代码。
查看报告结果
在StrictMode中有多种报告违规的形式,但是如果您想要分析特定的违规,您仍然需要检查日志。在终端下过滤严格模式,可以得到具体的违规stacktrace信息。
亚洲开发银行日志|严格模式
当然,你也可以选择弹窗简洁地提醒开发者。
弹出警告
ThreadPolicy 详解
严格模式。线程策略。生成器主要方法如下
检测网络()用于检查用户界面线程中是否有网络请求操作
检测用户界面线程中网络请求案例:
公共类主要活动扩展AppCompatActivity实现视图OnClickListener {
按钮btnTest
@覆盖
受保护的void onCreate(Bundle saved instancestate){
超级棒。oncreate(savedInstanceState);
setContentView(r . layout。活动_主);
StrictMode.setThreadPolicy(新严格模式.线程策略。构建器()。检测网络()。penaltyLog()。build());
BTN测试=(Button)findViewById(r . id。BTN _测试);
btntest。setonclicklistener(this);
}
@覆盖
公共void onClick(视图五){
int id=v . getid();
开关(id) {
案例编号btn_test:
邮网();
打破;
}
}
/**
* 网络连接的操作
*/
私有void postNetwork() {
尝试{
URL URL=新URL(' http://www。宇云。org’);
http URL connection conn=(http URL connection)URL。打开连接();
conn . connect();
缓冲读取器reader=新缓冲读取器(新输入流读取器(
conn . getinputstream()));
字符串行=空
字符串缓冲区sb=新字符串缓冲区();
while ((lines=reader.readLine())!=null) {
某人追加(行);
}
} catch(异常e) {
e。printstacktrace();
}
}
}
运行后,触发的警告如下
detectDiskReads()和detectDiskWrites()是磁盘读写检查
磁盘读写检查案例:
公共类主要活动扩展AppCompatActivity实现视图OnClickListener {
按钮btnTest
@覆盖
受保护的void onCreate(Bundle saved instancestate){
超级棒。oncreate(savedInstanceState);
setContentView(r . layout。活动_主);
StrictMode.setThreadPolicy(新严格模式.线程策略。构建器()。detectDiskWrites()。detectDiskReads()。penaltyLog()。build());
BTN测试=(Button)findViewById(r . id。BTN _测试);
btntest。setonclicklistener(this);
}
@覆盖
公共void onClick(视图五){
int id=v . getid();
开关(id) {
案例编号btn_test:
writeToExternalStorage();
打破;
}
}
/**
* 文件系统的操作
*/
public void writeToExternalStorage(){
文件外部存储=环境。getexternal存储目录();
文件MB文件=新文件(外部阶段,' casti El。txt’);
尝试{
输出流output=新文件输出流(MB文件,true);
output.write('www.wooyun.org ').getBytes());
输出。flush();
输出。close();
} catch(找不到文件异常e){
e。printstacktrace();
} catch (IOException e) {
e。printstacktrace();
}
}
}
运行后,触发的警告如下
noteSlowCall针对执行比较耗时的检查
严格模式从API 11开始允许开发者自定义一些耗时调用违例,这种自定义适用于自定义的任务执行类中,比如我们有一个进行任务处理的类,为任务执行者。
公共类任务执行者{
公共void execute(可运行任务){
task.run()。
}
}
先需要跟踪每个任务的耗时情况,如果大于500毫秒需要提示给开发者,noteSlowCall就可以实现这个功能,如下修改代码
公共类任务执行者{
私有静态长慢速呼叫阈值=500
公共void执行任务(可运行任务){
长启动时间=系统时钟。正常运行时间millis();
task.run()。
长成本=系统时钟。uptime millis()-开始时间;
如果(慢成本呼叫阈值){
严格模式。notes低呼('慢呼成本='成本);
}
}
}
执行一个耗时2000毫秒的任务
任务执行者executor=新任务执行者();
执行者.执行任务(新的Runnable() {
@覆盖
公共无效运行(){
尝试{
线程。睡眠(2000年);
} catch (InterruptedException e) {
e。printstacktrace();
}
}
});
得到的违例日志,注意其中~持续时间=20毫秒并非耗时任务的执行时间,而我们的自定义信息消息=慢速呼叫成本=2000才包含了真正的耗时。
penaltyDeath(),当触发违规条件时,直接碰撞掉当前应用程序。
penaltyDeathOnNetwork(),当触发网络违规时,崩溃掉当前应用程序。
penaltyDialog(),触发违规时,显示对违规信息对话框。
penaltyFlashScreen(),会造成屏幕闪烁,不过一般的设备可能没有这个功能。
penaltyDropBox(),将违规信息记录到dropbox系统日志目录中(/data/system/dropbox),你可以通过如下命令进行插件:
ADB shell转储系统Dropbox dataappstrictmode-打印
permitCustomSlowCalls()、permitDiskReads()、permitdiskwests()、permitNetwork:如果你想关闭某一项检测,可以使用对应的许可证*方法。
VMPolicy 详解
严格模式。虚拟机策略生成器主要方法如下
detectActivityLeaks()用户检查活动的内存泄露情况
内存泄露检查案例:
公共类主要活动扩展AppCompatActivity实现视图OnClickListener {
@覆盖
受保护的void onCreate(Bundle saved instancestate){
超级棒。oncreate(savedInstanceState);
setContentView(r . layout。活动_主);
StrictMode.setVmPolicy(新严格模式.虚拟机策略。构建器()。detectActivityLeaks()。penaltyLog()。构建()
);
新线程(){
@覆盖
公共无效运行(){
while (true) {
系统时钟。睡眠(1000);
}
}
}.start();
}
}
我们反复旋转屏幕就会输出提示信息(重点在实例=2;极限=1这一行)
这时因为,我们在活动中创建了一个线匿名内部类,而匿名内部类隐式持有外部类的引用。而每次旋转屏幕是,安卓会新创建一个活动,而原来的活动实例又被我们启动的匿名内部类线程持有,所以不会释放,从日志上看,当先系统中该活动有四个实例,而限制是只能创建一各实例。我们不断翻转屏幕,实例的个数还会持续增加。
detectLeakedClosableObjects()用于资源没有正确关闭时提醒
//资源引用没有关闭检查案例
公共类主要活动扩展AppCompatActivity实现视图OnClickListener {
@覆盖
受保护的void onCreate(Bundle saved instancestate){
超级棒。oncreate(savedInstanceState);
setContentView(r . layout。活动_主);
StrictMode.setVmPolicy(新严格模式.虚拟机策略。构建器()。detectLeakedClosableObjects()。penaltyLog()。构建()
);
File new xmlfile=新文件(环境。getexternalstoratedirectory(),' casti El。txt’);
尝试{
新XML文件。创建新文件();
FileWriter fw=new FileWriter(新的XML文件);
fw.write('猴子搬来的救兵woo yun’);
//fw。close();我们在这里特意没有关闭淡水
} catch (IOException e) {
e。printstacktrace();
}
}
}
运行后触发警告如下
detectLeakedSqlLiteObjects()和
detectLeakedClosableObjects()的用法类似,只不过是用来检查SQLiteCursor或者其他SQLite
对象是否被正确关闭
detectLeakedRegistrationObjects()用来检查广播接收机或者
服务连接注册类对象是否被正确释放
setClassInstanceLimit(),设置某个类的同时处于内存中的实例上限,可以协助检查内存泄露
检测内存泄露案例
公共类主要活动扩展AppCompatActivity实现视图OnClickListener {
私有静态类CastielClass{}
私有静态ListCastielClass类别列表
@覆盖
受保护的void onCreate(Bundle saved instancestate){
超级棒。oncreate(savedInstanceState);
setContentView(r . layout。活动_主);
class list=new ArrayListCastielClass();
StrictMode.setVmPolicy(新严格模式.虚拟机策略。构建器()。setClassInstanceLimit(castielclass。第二类)。penaltyLog()。build());
班级名单。add(new casti El class());
班级名单。add(new casti El class());
班级名单。add(new casti El class());
班级名单。add(new casti El class());
班级名单。add(new casti El class());
班级名单。add(new casti El class());
班级名单。add(new casti El class());
班级名单。add(new casti El class());
}
}
运行后触发警告如下
其他操作
除了查看日志,我们还可以在开发人员选项中打开严格模式。开启后,如果主线程中有长时间运行的操作,屏幕会闪烁,这是一个比较直接的方法。
注意事项
只在开发阶段启用StrictMode,发布应用或发布版本时一定要禁用。
该模式不能严格监控JNI中的磁盘IO和网络请求。
并不是所有的违例都需要在应用中解决,比如一些IO操作必须在主线程中执行。
总结
以上是边肖介绍的Android的StrictMode的详细说明。希望对你有帮助。如果您有任何问题,请给我留言,边肖将及时回复您。非常感谢您对我们网站的支持!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。