1. 原因分析
1.1 內存泄漏實例
首先看一個簡單的Handler引發內存泄漏的例子:
public class HandlerActivity extends Activity {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Const.NOTIFY_LOCATION_SUC:
boolean isSuc = (Boolean) msg.obj;
doLocation(isSuc);
break;
default:
break;
}
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
mHandler.sendEmptyMessageDelayed(Const.NOTIFY_LOCATION_SUC, 10000);
}
}
1.2 內存泄漏分析
Handler的引用阻止GC回收Activity
在Java中,非靜態(匿名)內部類會默認隱性引用外部類對象。
如果外部類是Activity就會造成內存泄漏Handler和Activity的生命週期不一致
就上面的例子而言,當Activity結束後,消息循環中還有延時消息,那麼Handler還會一直存在,知道所有消息處理完,但Handler引用了Activity,那麼就會阻止Activity被回收,造成內存泄漏。
2. 解決方式
(1)使用顯式引用
- 把Handler聲明爲靜態內部類,而靜態內部類不會引用外部類對象
- 把Handler聲明爲靜態外部類
(2)在handler中弱引用Activity
public class HandlerActivity extends Activity {
private static final int MSG_START_RECORDING = 0x1001;
private static final int MSG_STOP_RECORDING = 0x1002;
private WorkHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new WorkHandler(this);
}
public void start() {
mHandler.sendMessage(mHandler.obtainMessage(MSG_START_RECORDING));
}
public void stop() {
mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_RECORDING));
}
private static class WorkHandler extends Handler {
private WeakReference<HandlerActivity> mWeakActivity;
public WorkHandler(HandlerActivity activity) {
super();
mWeakActivity = new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
HandlerActivity activity = mWeakActivity.get();
switch (msg.what) {
case MSG_START_RECORDING:
activity.handleStartEncoding();
break;
case MSG_STOP_RECORDING:
activity.handleStopEncoding();
break;
}
}
}
private void handleStartEncoding() {
}
private void handleStopEncoding() {
}
}