线程优化是Android性能优化中一个非常重要的部分,作为进程中逻辑处理调度的基本单位,如果使用不当,非常容易造成系统资源的浪费,从而导致应用性能出问题。在日常开发中,最常出现的问题主要有两个方面,一是线程启动过多造成CPU和内存资源浪费,并且应用耗电过大;二是线程作为GCRoots,如果使用不当,容易直接或间接造成Activity无法销毁,导致内存泄漏。
本篇博文主要以这两点为基础,结合日常开发中遇到的场景,整理和分析下相应的优化策略。
一、无需使用线程的场景
虽然程序无时无刻不是运行在线程中,不过为了防止阻塞主线程(比如Android的UI线程),获得更加流畅的用户体验,像网络请求、数据库操作、IO操作、密集计算等,往往都需要开启一个异步工作线程,这是众所周知的道理。不过,往往因此导致了线程的滥用,下面我们来看一些无需使用线程却误用的场景。
1、延时任务
由于某些操作或者逻辑需要延时处理,比如延时2s设置一个按钮消失。大家都知道不能阻塞主线程,否则会导致页面无响应,然后就习惯性地开个线程。
new Thread() {
public void run() {
try {
Thread.sleep(3000);
} catch (Exception e) {
}
runOnUiThread(new Runnable() {
@Override
public void run() {
...
}
});
}
}.start();
当然,从功能运行和代码逻辑的角度上来看,这并没有问题。但是,如果这种操作过于频繁,或者sleep过长,很容易导致同时开启的线程过多。而且runOnUiThread里面基本都是视图相关的操作,而线程作为GCRoots之一,存活状态下关联的对象都是无法被回收的。所以像View、Activity等一系列对象销毁后内存都无法被回收导致内存泄漏,除非等到线程销毁后的下一次GC才能被回收掉。
那么,除了开线程sleep之外,还有什么方式执行延时任务呢?
推荐做法:利用主线程Handler消息机制的postDelay。如果延时前和延时后的执行环境都是在主线程中,那么利用利用Handler消息机制的delay功能,能够非常方便作延时处理。以上的代码,可以修改成:
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
...
}
}, 3000);
而如果你正好有一个任意的View可