Android StrictMode运行流程(推荐)

所属分类: 软件编程 / Android 阅读数: 41
收藏 0 赞 0 分享

什么是 StrictMode(严苛模式)

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

strictmode.java 这个类中设定了许多detect标志位例如 DETECT_NETWORK ,还有许多 penalty标志位例如 PENALTY_NETWORK , DETECT标志位决定strictmode是否要对这项内容进行检测,PENALTY标志位决定了在这项内容发生时是否要抛出异常(相当于一种惩罚机制,PENALTY的意思就是惩罚).

StrictMode 类的作用之一就是对这些标志位进行管理,通过 setThreadPolicy() 方法可以设定 Policy 变量中的mask值.

之后会将 POLICY 变量传入 BlockGuard 中,BlockGuard 运行在 Dalvik虚拟机中,对所有的异常操作进行统一的管理.

Android官方文档中对于strict mode 给出的解释

strictmode 是一种开发工具,引入它可以使你发现在开发过程中产生的问题,并修复它们.

在 application main thread中常有UI相关的操作和动画发生,strictmode可以在主线程中检测硬盘和网络相关的操作.将硬盘读写操作和网络相关操作挪出主线程可以使你的app更加流畅和具有响应性.同时为了使app更加响应性,你可以屏蔽ANR发生时弹出的dialog.

需要注意的是,尽管android设备的硬盘类型大多为 flash memory,建立在这种存储介质上的文件系统的并发性仍然是非常有限的(速度上肯定是RAM比较快).

大部分情况下,硬盘的读写操作都是非常快的,但在某些情况下,后台进程中会运行耗费很大的I/O操作,在这种情况下,app的响应速度会下降很多.

一.setThreadPolicy()流程

StrictMode类的文档中给出的strictmode启动方式

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

1.

在执行了 setThreadPolicy()函数后会调用 setThreadPolicyMask()方法.

 public static void setThreadPolicy(final ThreadPolicy policy) {
 setThreadPolicyMask(policy.mask);
 }

2.

在 setThreadPolicyMask()方法中,除了在java层的threadLocal中设置外,还需要在Native层也进行一个设置.  

private static void setThreadPolicyMask(final int policyMask) {
 // In addition to the Java-level thread-local in Dalvik's
 // BlockGuard, we also need to keep a native thread-local in
 // Binder in order to propagate the value across Binder calls,
 // even across native-only processes. The two are kept in
 // sync via the callback to onStrictModePolicyChange, below.
 setBlockGuardPolicy(policyMask);
 // And set the Android native version...
 Binder.setThreadStrictModePolicy(policyMask);
 }

3.

首先分析java层的 setBlockGuardPolicy()方法.

如果policyMask==0,会返回一个默认policy,默认policy不进行任何设置和检测,policy对象存储在threadLocal变量中(每个线程保存一个policy的对象),首次运行该方法会生成一个默认policy(mMask=0)保存在threadLocal中,这里的policy对象是AndroidBlockGuardPolicy类型.   

// Sets the policy in Dalvik/libcore (BlockGuard)
 private static void setBlockGuardPolicy(final int policyMask) {
 if (policyMask == 0) {
 BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
 return;
 }
 final BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
 final AndroidBlockGuardPolicy androidPolicy;
 if (policy instanceof AndroidBlockGuardPolicy) {
 androidPolicy = (AndroidBlockGuardPolicy) policy;
 } else {
 androidPolicy = threadAndroidPolicy.get();
 BlockGuard.setThreadPolicy(androidPolicy);
 }
 androidPolicy.setPolicyMask(policyMask);
 }

4.

再看Native层的代码:

设置了policy

386void IPCThreadState::setStrictModePolicy(int32_t policy)
387{
388 mStrictModePolicy = policy;
389}

二.StrictMode如何检测问题.

1.

CloseGuard检测游标是否正常关闭:

当使用ContentResolver来查询数据库的时候,会返回一个CursorWrapperInner类型的Cursor对象.

mCursor = mResolver.query(mUri, null, null, null, null);

CloseGuard对CursorWrapperInner是否正常关闭的检测的逻辑在finalize()函数中,finalize()会在gc执行垃圾回收的时候被调用(垃圾回收使用了GcRoot算法)

如果没有执行CursorWrapperInner的close()函数,仅将CursorWrapperInner对象置为null,当主动触发gc的时候( Systemgc()),finalize()函数被调用 ,"Cursor finalized without prior close()"这段log被打印.但如果没有将CursorWrapperInner对象置为null,这时主动触发gc并不会引起 finalize()函数的执行,因为CursorWrapperInner对象被强引用,垃圾回收器在回收时不会考虑回收强引用对象,即使最后内存不足而崩溃.

经过测试程序的测试,发现"Cursor finalized without prior close()"这段log在 CursorWrapperInner对象置空并执行 System.gc()后是会打印出来的.

但是 CloseGuard中的 warnIfOpen()函数始终没有执行

在 CursorWrapperInner的构造函数中,mCloseGuard执行 open()函数,在 open函数中allocationSite被赋值,而 ENABLED 变量是默认为true的,唯一改变它的setEnabled()方法在源码中也并没有被调用,所以应该是会在REPORTER中打印SystemLog的,但最后SystemLog并没有打印,具体原因分析不出来.       

@Override
 protected void finalize() throws Throwable {
 try {
 if (mCloseGuard != null) {
  mCloseGuard.warnIfOpen();
 }
 if (!mProviderReleased && mContentProvider != null) {
  // Even though we are using CloseGuard, log this anyway so that
  // application developers always see the message in the log.
  Log.w(TAG, "Cursor finalized without prior close()");
  ContentResolver.this.releaseProvider(mContentProvider);
 }
 } finally {
 super.finalize();
 }
 }
 }
 public void warnIfOpen() {
 if (allocationSite == null || !ENABLED) {
 return;
 }
 String message = 
 ("A resource was acquired at attached stack trace but never released. "
  + "See java.io.Closeable for information on avoiding resource leaks.");
 REPORTER.report(message, allocationSite);
 }
 @Override public void report (String message, Throwable allocationSite) {
 System.logW(message, allocationSite);
 }
 CursorWrapperInner(Cursor cursor, IContentProvider icp) {
 super(cursor);
 mContentProvider = icp;
 mCloseGuard.open("close");
 }

2.

onSqliteObjectsLeaked()也是用来检测数据库游标有没有正常关闭,但这个函数检测的是通过SqliteDataBase. query()得到的SqliteCursor游标对象.

检测位置也是在 finalize()函数中.

 /**
 * Release the native resources, if they haven't been released yet.
 */
 @Override
 protected void finalize() {
 try {
 // if the cursor hasn't been closed yet, close it first
 if (mWindow != null) {
 if (mStackTrace != null) {
  String sql = mQuery.getSql();
  int len = sql.length();
  StrictMode.onSqliteObjectLeaked(
  "Finalizing a Cursor that has not been deactivated or closed. " +
  "database = " + mQuery.getDatabase().getLabel() +
  ", table = " + mEditTable +
  ", query = " + sql.substring(0, (len > 1000) ? 1000 : len),
  mStackTrace);
 }
 close();
 }
 } finally {
 super.finalize();
 }
 }

流程如下图

三.StrictMode中使用到的桥接模式

桥接模式:所谓桥接模式就是将逻辑的抽象与实现分开的一种模式

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

更多精彩内容其他人还在看

Android异常 java.lang.IllegalStateException解决方法

这篇文章主要介绍了Android异常 java.lang.IllegalStateException解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android中Split()字符串分割特殊用法案例详解

本文通过案例的形式给大家详细介绍了android中split()字符串分割特殊用法的知识,非常不错具有参考借鉴价值,感兴趣的朋友参考下
收藏 0 赞 0 分享

Android仿新浪微博启动界面或登陆界面(1)

这篇文章主要为大家详细介绍了Android仿新浪微博启动界面或登陆界面的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android仿新浪微博oauth2.0授权界面实现代码(2)

这篇文章主要为大家详细介绍了Android仿新浪微博oauth2.0授权界面实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android开发中使用sqlite实现新闻收藏和取消收藏的功能

本篇文章主要介绍了sqlite实现新闻收藏和取消收藏功能,主要涉及到oracle数据库方面的内容,对于Android开发sqlite实现收藏和取消功能感兴趣的朋友可以参考下本文
收藏 0 赞 0 分享

Android仿新浪微博分页管理界面(3)

这篇文章主要为大家详细介绍了Android仿新浪微博分页管理界面,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android UI自定义ListView实现下拉刷新和加载更多效果

这篇文章主要介绍了Android UI自定义ListView实现下拉刷新和加载更多效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android—基于微信开放平台v3SDK开发(微信支付填坑)

这篇文章主要介绍了Android—基于微信开放平台v3SDK开发(微信支付填坑),具有一定的参考价值,有需要的可以了解一下。
收藏 0 赞 0 分享

Android仿新浪微博自定义ListView下拉刷新(4)

这篇文章主要为大家详细介绍了Android仿新浪微博自定义ListView下拉刷新,重点介绍了Adapter的详细代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android控件之使用ListView实现时间轴效果

这篇文章主要介绍了Android基础控件之使用ListView实现时间轴效果的相关资料,本文是以查看物流信息为例,给大家介绍了listview时间轴的实现代码,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多