我们先来看下日常Handler的一般用法:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//主线程创建时便自动创建Looper和对应的MessageQueue,之前执行Loop()进入消息循环
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化Handler
//这里并无指定Looper,即自动绑定当前线程(主线程)的Looper和MessageQueue
private Handler showhandler = new Handler(){
//通过复写handlerMessage()从而决定如何进行更新UI操作
@Override
public void handleMessage(Message msg) {
//UI更新操作
}
};
//启动子线程
new Thread(){
@Override
public void run() {
super.run();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
showhandler.sendEmptyMessageDelayed(0x1,10000);
}
}
}.start();
finish();
}
在上面的例子中,你会发现出现了严重的警告:
从上图可以看出来,这个警告的原因是:该Handler造成了严重的内存泄漏
那么,该Handler是怎么样造成内存泄露的呢?
根据图片可以分析,内存泄露显示出现在:
首先,我们需要了解到:
在了解到上述两条后,从上面的代码中可以知道:
上面提到,在Java里,非静态内部类和匿名类都会潜在的引用它们所属的外部类。 但是,静态内部类不会。
所以,避免内存泄露的解决方案是:只需要将Handler的子类设置成静态内部类
解决代码如下:
public class MainActivity extends AppCompatActivity {
//将Handler改成静态内部类
private static class FHandler extends Handler{
//定义弱引用实例
private WeakReference<Activity> reference;
//在构造方法中传入需要持有的Activity实例
public MyHandler(Activity activity) {
reference = new WeakReference<Activity>(activity); }
//通过复写handlerMessage()从而决定如何进行更新UI操作
@Override
public void handleMessage(Message msg) {
//省略代码
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
//主线程创建时便自动创建Looper和对应的MessageQueue,之前执行Loop()进入消息循环
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化Handler的子类
//这里并无指定Looper,即自动绑定当前线程(主线程)的Looper和MessageQueue
private final Handler showhandler = new FHandler();
//启动子线程
new Thread(){
@Override
public void run() {
super.run();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
showhandler.sendEmptyMessageDelayed(0x1,10000);
}
}
}.start();
}
代码如下:
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
经过上述两个解决方案,在Handler里的内存泄露问题就不会再出现了!