性能优化工具(一)StrictMode使用

一、简介:
StrictMode类是Android 2.3 (API 9)引入的一个工具类,可以用来帮助开发者发现代码中的一些不规范的问题,以达到提升应用响应能力的目的。举个例子来说,如果开发者在UI线程中进行了网络操作或者文件系统的操作,而这些缓慢的操作会严重影响应用的响应能力,甚至出现ANR对话框。为了在开发中发现这些容易忽略的问题,我们使用StrictMode,系统检测出主线程违例的情况并做出相应的反应,最终帮助开发者优化和改善代码逻辑。
二、用途:
使用严格模式,系统检测出主线程违例的情况会做出相应的反应,如日志打印,弹出对话框亦或如日志打印,弹出对话框亦或通过一定的方式暴露给开发者方便优化与改善。
三、使用:

private boolean DEV_MODE = true;
 public void onCreate() {
     if (DEV_MODE) {
         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                 .detectCustomSlowCalls() //API等级11,使用StrictMode.noteSlowCode
                 .detectDiskReads()
                 .detectDiskWrites()
                 .detectNetwork()   // or .detectAll() for all detectable problems
                 .penaltyDialog() //弹出违规提示对话框
                 .penaltyLog() //在Logcat 中打印违规异常信息
                 .penaltyFlashScreen() //API等级11
                 .build());
         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                 .detectLeakedSqlLiteObjects()
                 .detectLeakedClosableObjects() //API等级11
                 .penaltyLog()
                 .penaltyDeath()
                 .build());
     }
     super.onCreate();
 }

ThreadPolicy线程策略检测

  • 线程策略检测的内容有
  • 自定义的耗时调用 使用detectCustomSlowCalls()开启
  • 磁盘读取操作 使用detectDiskReads()开启
  • 磁盘写入操作 使用detectDiskWrites()开启
  • 网络操作 使用detectNetwork()开启

VmPolicy虚拟机策略检测

  • Activity泄露 使用detectActivityLeaks()开启
  • 未关闭的Closable对象泄露 使用detectLeakedClosableObjects()开启
  • 泄露的Sqlite对象 使用detectLeakedSqlLiteObjects()开启
  • 检测实例数量 使用setClassInstanceLimit()开启

ThreadPolicy 详解

  • detectLeakedSqlLiteObjects() 和detectLeakedClosableObjects()的用法类似,只不过是用来检查 SQLiteCursor 或者 其他 SQLite对象是否被正确关闭
  • detectLeakedRegistrationObjects() 用来检查 BroadcastReceiver 或者ServiceConnection 注册类对象是否被正确释放
  • setClassInstanceLimit(),设置某个类的同时处于内存中的实例上限,可以协助检查内存泄露
  • detectLeakedClosableObjects()用于资源没有正确关闭时提醒
  • detectActivityLeaks() 用户检查 Activity 的内存泄露情况
  • detectDiskReads() 和 detectDiskWrites() 是磁盘读写检查
  • noteSlowCall针对执行比较耗时的检查
  • penaltyDeath(),当触发违规条件时,直接Crash掉当前应用程序。
  • penaltyDeathOnNetwork(),当触发网络违规时,Crash掉当前应用程序。
  • penaltyDialog(),触发违规时,显示对违规信息对话框。
  • penaltyFlashScreen(),会造成屏幕闪烁,不过一般的设备可能没有这个功能。
  • penaltyDropBox(),将违规信息记录到 dropbox 系统日志目录中(/data/system/dropbox),你可以通过如下命令进行插件:

StrictMode.ThreadPolicy.Builder 主要方法如下
1、detectNetwork() 用于检查UI线程中是否有网络请求操作

public class MainActivity extends Activity implements View.OnClickListener{
    private Button btnTest;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectNetwork()
                .penaltyLog()
                .build());
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnTest = (Button) findViewById(R.id.button);
        btnTest.setOnClickListener(MainActivity.this);

    }
    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.button:
                postNetwork();
                break;
        }
    }
    /**
     * 网络连接的操作
     */
    private void postNetwork() {
        try {
            URL url = new URL("http://www.wooyun.org");
            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);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
 }

运行后,触发的警告如下

2020-01-03 15:00:33.422 8120-8120/com.zqc.testdemo D/StrictMode: StrictMode policy violation; ~duration=13 ms: android.os.StrictMode$StrictModeNetworkViolation: policy=65540 violation=4
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1456)
        at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:102)
        at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
        at java.net.InetAddress.getAllByName(InetAddress.java:787)
        at com.android.okhttp.Dns$1.lookup(Dns.java:39)
        at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:175)
        at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:141)
        at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:83)
        at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:174)
        at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
        at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
        at com.zqc.testdemo.MainActivity.postNetwork(MainActivity.java:52)
        at com.zqc.testdemo.MainActivity.onClick(MainActivity.java:41)
        at android.view.View.performClick(View.java:6311)
        at android.view.View$PerformClick.run(View.java:24829)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6752)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:449)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

2、setClassInstanceLimit(),设置某个类的同时处于内存中的实例上限,可以协助检查内存泄露

public class MainActivity extends Activity{
    private static class CastielClass{}
    private static List<CastielClass> classList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectNetwork()
                .penaltyLog()
                .build());
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        classList = new ArrayList<CastielClass>();
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .setClassInstanceLimit(CastielClass.class, 2)
                .penaltyLog()
                .build());

        classList.add(new CastielClass());
        classList.add(new CastielClass());
        classList.add(new CastielClass());
        classList.add(new CastielClass());
        classList.add(new CastielClass());
        classList.add(new CastielClass());
        classList.add(new CastielClass());
        classList.add(new CastielClass());


    }


}

运行之后会有如下警告:

2020-01-03 15:14:56.556 11331-11331/com.zqc.testdemo E/StrictMode: class com.zqc.testdemo.MainActivity$CastielClass; instances=8; limit=2
    android.os.StrictMode$InstanceCountViolation: class com.zqc.testdemo.MainActivity$CastielClass; instances=8; limit=2
        at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

3、detectActivityLeaks() 用户检查 Activity 的内存泄露情况

public class MainActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectActivityLeaks()
                .penaltyLog()
                .build()
        );

        new Thread() {
            @Override
            public void run() {
                while (true) {

                    SystemClock.sleep(1000);
                }
            }
        }.start();

    }
}

运行如下所示:

2020-01-03 15:35:33.045 3459-3459/? D/StrictMode: StrictMode policy violation; ~duration=91 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=65599 violation=2
        at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1440)
        at java.io.UnixFileSystem.checkAccess(UnixFileSystem.java:251)
        at java.io.File.exists(File.java:807)
        at android.app.ContextImpl.getDataDir(ContextImpl.java:2197)
        at android.app.ContextImpl.getPreferencesDir(ContextImpl.java:517)
        at android.app.ContextImpl.getSharedPreferencesPath(ContextImpl.java:714)
        at android.app.ContextImpl.getSharedPreferences(ContextImpl.java:368)
        at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:167)
        at android.preference.PreferenceManager.getDefaultSharedPreferences(PreferenceManager.java:526)
        at com.sprd.providers.contacts.FSA.<init>(SyncSimAccountsReceiver.java:202)
        at com.sprd.providers.contacts.FSA.getInstance(SyncSimAccountsReceiver.java:146)
        at com.sprd.providers.contacts.SyncSimAccountsReceiver.onReceive(SyncSimAccountsReceiver.java:865)
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:3296)
        at android.app.ActivityThread.-wrap18(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1733)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6752)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:449)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值