美文网首页安卓之美AndroidAndroid
Android探索之旅 | StrictMode严苛模式

Android探索之旅 | StrictMode严苛模式

作者: 程序员联盟 | 来源:发表于2016-08-02 14:08 被阅读6004次

    -- 作者 谢恩铭 转载请注明出处

    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<Activity> sLeakyActivities = new ArrayList<Activity>();
    }
     
    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(开发者选项),然后开启它。开启之后,一旦应用在主线程中执行耗时操作,屏幕就会闪烁。

    在开发者选项中开启StrictMode

    人世间,
    万千情感皆有温度,
    千万代码似有性格。
    这里有原创教程,IT丛林......
    和你一起探索程序人生。
    我是谢恩铭,在巴黎奋斗的嵌入式软件工程师。
    个人简介
    热爱生活,喜欢游泳,略懂烹饪。
    人生格言:“向着标杆直跑”

    相关文章

      网友评论

      本文标题:Android探索之旅 | StrictMode严苛模式

      本文链接:https://www.haomeiwen.com/subject/qslfsttx.html