Android性能优化之StrictMode 的使用

概述

  • StrictMode类自Android 2.3 (API 9)引入,用于监测程序中的违例情况。
  • 提供了各种策略,比如监视网络访问 和 磁盘读写操作.当开发者违背了事先设定的规则的时候,就会通过不同的方法去提醒开发者改善代码.

官方文档:
developer.android.com/reference/android/os/StrictMode.html

概念

翻译过来就是严格模式 的意思。

4.0之后,如在主线程进行访问网络,则会抛NetworkOnMainThreadException异常,但在4.0之前,android允许主线程(UI线程)网络访问。

而且,像数据库操作和磁盘操作,等耗时任务则没有严格的限制。

使用StrictMode.系统则会监测这些违例并做出反应,如日志打印,弹出对话框等.

使用

可以放在Application或者Activity的onCreate()中,为了全面监测,建议放在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();
 }

注意:

  • 因为会提醒用户,所以严格模式需要在debug 模式下开启
  • 严格模式在Android2.3中引入的,在API>=9后才可以使用

监控策略

严格模式主要检测两大问题,一个是线程策略,即TreadPolicy,主要用于监测主线程中耗时操作.
另一个是VM策略,即VmPolicy,主要用于发现内存问题

ThreadPolicy

detectCustomSlowCalls().监测自定义的耗时操作
detectDiskReads().监测磁盘读取操作
detectDiskWrites().监测磁盘写入操作
detectNetwork().监测网络操作

permitCustomSlowCalls()permitDiskReads()permitDiskWrites()permitNetwork()对应的用于关闭某一项的监测.

VmPolicy

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信息,我们可以知道是因为耗时的磁盘操作造成的

detectCustomSlowCalls()

监测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:

我们可以从信息中看到某个方法执行了多长时间,但是这个时间一般是要比实际值要高那么一点点的.

常见解决办法

  • 网络操作采用Handler传递消息
  • SharedPreferences采用apply等
  • 耗时操作放到子线程中来完成

内存泄露监测

    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)

常见解决办法

  • Handler使用Activity的若引用的方法来避免泄露
  • 数据库操作完毕,要关闭Cursor,及时关闭Closable对象
  • 在 onDestroy() 方法中将 receiver 释放掉unregisterReceiver(this.receiver);

参考:Android性能调优利器StrictMode

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值