Android性能优化之StrictMode

2021-08-17  本文已影响0人  itfitness

目录

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一样的信息:


上一篇下一篇

猜你喜欢

热点阅读