热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

AndroidStrictMode运行流程(推荐)

strictmode是android在API9后引入的检测影响app运行流畅性的一种机制。这篇文章给大家介绍了androidstrictmode运行流程,需要的朋友参考下吧

什么是 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自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • SQLite 动态创建多个表的需求在网络上有不少讨论,但很少有详细的解决方案。本文将介绍如何在 Qt 环境中使用 QString 类轻松实现 SQLite 表的动态创建,并提供详细的步骤和示例代码。 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • 本文详细介绍如何使用arm-eabi-gdb调试Android平台上的C/C++程序。通过具体步骤和实用技巧,帮助开发者更高效地进行调试工作。 ... [详细]
  • Søren Kierkegaard famously stated that life can only be understood in retrospect but must be lived moving forward. This perspective delves into the intricate relationship between our lived experiences and our reflections on them. ... [详细]
  • 计算机网络复习:第五章 网络层控制平面
    本文探讨了网络层的控制平面,包括转发和路由选择的基本原理。转发在数据平面上实现,通过配置路由器中的转发表完成;而路由选择则在控制平面上进行,涉及路由器中路由表的配置与更新。此外,文章还介绍了ICMP协议、两种控制平面的实现方法、路由选择算法及其分类等内容。 ... [详细]
  • 本文将介绍如何使用 Go 语言编写和运行一个简单的“Hello, World!”程序。内容涵盖开发环境配置、代码结构解析及执行步骤。 ... [详细]
  • 线性Kalman滤波器在多自由度车辆悬架主动控制中的应用研究
    本文探讨了线性Kalman滤波器(LKF)在不同自由度(2、4、7)的车辆悬架系统中进行主动控制的应用。通过详细的仿真分析,展示了LKF在提升悬架性能方面的潜力,并总结了调参过程中的关键要点。 ... [详细]
  • 精选30本C# ASP.NET SQL中文PDF电子书合集
    欢迎订阅我们的技术博客,获取更多关于C#、ASP.NET和SQL的最新资讯和资源。 ... [详细]
  • MySQL 数据库迁移指南:从本地到远程及磁盘间迁移
    本文详细介绍了如何在不同场景下进行 MySQL 数据库的迁移,包括从一个硬盘迁移到另一个硬盘、从一台计算机迁移到另一台计算机,以及解决迁移过程中可能遇到的问题。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
  • 本文介绍如何在 FireDAC 环境下实现 FDMEMTable 字段的自动获取,为开发人员提供便捷的数据处理方式。 ... [详细]
author-avatar
暗影HK4164286
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有