StrictMode是一个开发者工具,它可以帮助我们监测到在大量代码中运行在主线程中我们不容易发现的耗时操作,这些耗时操作显然是放错了位置的,他们应该在工作线程中运行,如果我们自己一行一行去发现这种错误,代码少的话还可以,代码一多,这显然是不可能做到的事情。
我们的UI有时候会有卡顿,这也是因为我们不小心在主线程UI中放置了耗时的操作,比如我们有一个listview,滑动起来很卡顿,那很有可能是我们把一些磁盘读写操作或者网络操作放到的主线程中去了,UI线程是用来展示数据和动画的,将磁盘和网络操作放到其他线程会使得UI线程运行的更加流畅,响应更加及时,而且还可以避免ANR。
我们在Application或者Activity中的onCreate()方法中加入如下代码,就可以进行监测了
public void onCreate() { //定义一个开关,在测试版本中为true 在正式版本中为false if (DEVELOPER_MODE) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() //监测磁盘读 .detectDiskReads() //监测磁盘写 .detectDiskWrites() //监测网络 .detectNetwork() //.detectAll() 监测所有 //打印日志 .penaltyLog() .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() //监测数据库对象泄露 .detectLeakedSqlLiteObjects() //监测可关闭的对象泄露 .detectLeakedClosableObjects() //打印日志 .penaltyLog() //在最后调用,关闭监测器进程,但是不影响log打印 .penaltyDeath() .build()); } super.onCreate(); }
接下来我们来测试一下,我有一个项目,需要用到数据库,我将数据库的插入写在了UI线程中,我们来监测一下,看看打印的log
public class MainActivity extends Activity { private DaoMaster mDaoMaster; private DaoSession mDaoSession; private PersonDao personDao; //定义一个开关,在我们发布正式版本的时候,要记得改为false。在测试版本的时候,改为true private static final boolean DEVELOPER = true; @Override protected void onCreate(Bundle savedInstanceState) { //如果是测试版本的话 if (DEVELOPER) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() //detectAll()是监测所有,包括读磁盘 写磁盘 网络等 .detectAll() //将监测信息打印到logcat中 .penaltyLog() .build()); } super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDaoSession = MyApplication.getDaoSession(getApplicationContext()); personDao = mDaoSession.getPersonDao(); personDao.deleteAll(); Person p1 = new Person(1l, "zhangyi","1"); Person p2 = new Person(2l, "zhangyi","2"); Person p3 = new Person(3l, "zhangsan","5"); Person p4 = new Person(4l, "zhangyi","4"); Person p5 = new Person(5l, "zhangwu","1"); personDao.insert(p1); personDao.insert(p2); personDao.insert(p3); personDao.insert(p4); personDao.insert(p5); QueryBuilder<Person> queryBuilder = personDao.queryBuilder(); List<Person> list = queryBuilder.where(Properties.Id.ge(2l), Properties.Name.eq("zhangyi")).list(); }
我们看第一行,这个耗时操作耗时302ms,violation=1说明有一个耗时操作在主线程中运行了,耗费了302ms的时间,这无疑会造成UI的卡顿。而且通过分析下面的信息我们可以得知,这个耗时操作是写磁盘操作。所以通过StrictMode可以非常清楚的发现我们项目中潜在的性能问题。
那么,现在我将数据库操作放到一个工作线程中去执行
public class MainActivity extends Activity { private DaoMaster mDaoMaster; private DaoSession mDaoSession; private PersonDao personDao; //定义一个开关,在我们发布正式版本的时候,要记得改为false。在测试版本的时候,改为true private static final boolean DEVELOPER = true; @Override protected void onCreate(Bundle savedInstanceState) { //如果是测试版本的话 if (DEVELOPER) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() //detectAll()是监测所有,包括读磁盘 写磁盘 网络等 .detectAll() //将监测信息打印到logcat中 .penaltyLog() .build()); } super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //开启一个线程去执行数据库操作 new Thread(new Runnable() { @Override public void run() { mDaoSession = MyApplication.getDaoSession(getApplicationContext()); personDao = mDaoSession.getPersonDao(); personDao.deleteAll(); Person p1 = new Person(1l, "zhangyi","1"); Person p2 = new Person(2l, "zhangyi","2"); Person p3 = new Person(3l, "zhangsan","5"); Person p4 = new Person(4l, "zhangyi","4"); Person p5 = new Person(5l, "zhangwu","1"); personDao.insert(p1); personDao.insert(p2); personDao.insert(p3); personDao.insert(p4); personDao.insert(p5); QueryBuilder<Person> queryBuilder = personDao.queryBuilder(); List<Person> list = queryBuilder.where(Properties.Id.ge(2l), Properties.Name.eq("zhangyi")).list(); } }).start(); ; }
运行后我们发现logcat中没有打印任何关于StrictMode的警告信息。说明我们的UI线程非常流畅
因此StrictMode是一个非常有用的工具,使用这个工具我们可以找到并修复一些微小的性能问题,像对象泄露等非常难发现的问题。所以,你的项目中使用StrictMode了吗?
作者:阿拉灯神灯