美文网首页
Android性能优化之StrictMode

Android性能优化之StrictMode

作者: itfitness | 来源:发表于2021-08-17 15:11 被阅读0次

    目录

    StrictMode是什么

    StrictMode从字面上翻译是严格模式的意思,它是Android提供的一种用来检测应用运行性能(耗时操作和内存泄漏等)的机制,它包含两大策略:线程策略(TreadPolicy)VM策略(VmPolicy)

    ThreadPolicy线程策略:

    自定义耗时检测:detectCustomSlowCalls()
    磁盘读取耗时检测:detectDiskReads()
    磁盘写入耗时检测:detectDiskWrites()
    网络耗时检测:detectNetwork()

    VmPolicy虚拟机策略:

    Activity泄漏检测:detectActivityLeaks()
    Closable对象泄漏检测:detectLeakedClosableObjects()
    Sqlite对象检测:detectLeakedSqlLiteObjects()
    实例数量检测:setClassInstanceLimit()

    StrictMode怎么使用

    StrictMode的使用方法非常简单,只需要在Application或者Activity中的onCreate()方法中加入如下代码即可:

    public class MyApplication extends Application {
        public static ArrayList<Activity> sLeakyActivities = new ArrayList<Activity>();
        @Override
        public void onCreate() {
            //配置ThreadPolicy策略
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads()
                    .detectDiskWrites()
                    .detectNetwork()
                    .penaltyLog()
                    .build());
            //配置VmPolicy策略
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectLeakedSqlLiteObjects()
                    .detectLeakedClosableObjects()
                    .penaltyLog()
                    .penaltyDeath()
                    .build());
            super.onCreate();
        }
    }
    

    当然如果对于ThreadPolicy策略你只想检测磁盘读的操作那么只需这样配置就行:

    //配置ThreadPolicy策略
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads()
                    .penaltyLog()
                    .build());
    

    如果你想将所有的都进行检测那么你可以进行这样简写:

            //配置ThreadPolicy策略
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectAll()//检测所有
                    .penaltyLog()
                    .build());
    

    我们已经将检测的代码写好了,接下来我们就可以通过运行APP然后就可以用Logcat或者adb命令查看检测到的问题了,这里为了展示的清晰我就对ThreadPolicy策略和VmPolicy策略分开来说了

    ThreadPolicy策略

    这里我在Application类中只设置ThreadPolicy

    public class MyApplication extends Application {
        public static ArrayList<Activity> sLeakyActivities = new ArrayList<Activity>();
        @Override
        public void onCreate() {
            //配置ThreadPolicy策略
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskWrites()//检测磁盘写
                    .penaltyLog()
                    .build());
            super.onCreate();
        }
    }
    

    然后我们在MainActivity的主线中加入一段写入磁盘的操作:

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            try {
                File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"DiskWrite.txt");
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                fileOutputStream.write("DiskWriteDiskWrite".getBytes());
                fileOutputStream.flush();
                fileOutputStream.close();
            }catch (Exception e){
            }
        }
    }
    

    我们运行APP会发现Logcat打印出了如下信息:



    我们可以看到Logcat中打印出了出现性能问题的具体位置,这时我们只需要找到并且修改为子线程处理即可:

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"DiskWrite.txt");
                        FileOutputStream fileOutputStream = new FileOutputStream(file);
                        fileOutputStream.write("DiskWriteDiskWrite".getBytes());
                        fileOutputStream.flush();
                        fileOutputStream.close();
                    }catch (Exception e){
                    }
                }
            }).start();
        }
    }
    

    当然我们也可以自定义一个检测如:

    //MyApplication 中增加自定义检测的配置
    public class MyApplication extends Application {
        public static ArrayList<Activity> sLeakyActivities = new ArrayList<Activity>();
        @Override
        public void onCreate() {
            //配置ThreadPolicy策略
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskWrites()//检测磁盘写
                    .detectCustomSlowCalls()//自定义检测
                    .penaltyLog()
                    .build());
            super.onCreate();
        }
    }
    
    //MainActivity 使用StrictMode.noteSlowCall()增加自定义检测
    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //自定义检测
            long start = System.currentTimeMillis();
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background);
            long useTime = System.currentTimeMillis() - start;
            if(useTime > 3){
                StrictMode.noteSlowCall("自定义耗时:" + useTime + "毫秒");
            }
        }
    }
    

    运行结果如下:


    VmPolicy策略

    这里我们先看一下Activity的内存泄漏的检测配置及效果:

    public class MyApplication extends Application {
        //用于保存Activity,以产生内存泄漏
        public static ArrayList<Activity> LEAKY_ACTIVITIES = new ArrayList<Activity>();
        @Override
        public void onCreate() {
            //配置VmPolicy策略
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectActivityLeaks()//Activity内存泄漏检测
                    .penaltyLog()
                    .build());
            super.onCreate();
        }
    }
    

    在MainActivity中加入一个按钮,点击后跳转LeaksActivity

    public class MainActivity extends AppCompatActivity {
        private Button btJump;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            btJump = (Button) findViewById(R.id.bt_jump);
            btJump.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startActivity(new Intent(MainActivity.this,LeaksActivity.class));
                }
            });
        }
    }
    

    在LeaksActivity中我们保存LeaksActivity的实例

    public class LeaksActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_leaks);
            MyApplication.LEAKY_ACTIVITIES.add(this);
        }
    }
    

    然后我们运行APP,多点几次跳转按钮



    我们可以在Logcat中看到,它告诉我们应该有一个实例而我们当前却有三个
    另外我们也可以使用setClassInstanceLimit配置自定义的对象实例数量的检测,如下:
    //配置VmPolicy策略
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectActivityLeaks()//Activity内存泄漏检测
                    .setClassInstanceLimit(TestUtil.class,1)//自定义的实例检测(超过1个了就提示)
                    .penaltyLog()
                    .build());
    

    接下来我们再看看未关闭的Closable对象的检测,我们调整VmPolicy策略的配置如下

    //配置VmPolicy策略
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectActivityLeaks()//Activity内存泄漏检测
                    .setClassInstanceLimit(TestUtil.class,1)//自定义的实例检测(超过1个了就提示)
                    .detectLeakedClosableObjects()//Closable对象未关闭检测
                    .penaltyLog()
                    .build());
    

    然后在LeaksActivity 中添加一段子线程中写文件的操作,但是不给close

    new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"closeable.txt");
                        FileOutputStream fileOutputStream = new FileOutputStream(file);
                        fileOutputStream.write("LeakedClosableObjects".getBytes());
                        fileOutputStream.flush();
                    }catch (Exception e){
                    }
                }
            }).start();
    

    然后我们跳转到LeaksActivity 中然后返回会出现如下提示:



    补充

    这里我再说下如何使用adb shell查看StrictMode的信息
    首先我们用adb shell 命令进入手机



    然后使用如下命令:

    logcat|grep StrictMode
    

    然后如果有检测到性能问题的话就会出现跟Logcat一样的信息:


    相关文章

      网友评论

          本文标题:Android性能优化之StrictMode

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