Android性能优化之StrictMode 的使用

来源:互联网 发布:淘宝网开店需要钱吗 编辑:程序博客网 时间:2024/06/05 20:52

概述

  • 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 0
原创粉丝点击