参考文献出处:https://github.com/xitu/gold-miner/blob/master/TODO/android-handler-internals.md
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Ping";
private Handler handler;
class PingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "Ping message received");
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new PingHandler();
final Message msg = handler.obtainMessage();
handler.sendEmptyMessageDelayed(0, TimeUnit.MINUTES.toMillis(1));
}
}
例子中handler.obtainMessage()生成的message的taarget会持有一个PingHandler对象的强应用,而PingHandler是非静态内部类,会隐式的持有Activity的应用,所以如果activity已经被销毁,但handle发送的message还没处理完的话便会发生内存泄露。
解决方法:
1、将PingHandler声明为静态内部类(静态内部类不会持有外部类应用);
2、使用弱引用(当 Activity 被销毁时,弱引用允许垃圾回收器去回收你想要留存的对象(通常来说是 Activity))。
使用弱引用:
static class UIHandler extends Handler {
private final WeakReference<ImageFetcherActivity> mActivityRef;
UIHandler(ImageFetcherActivity activity) {
mActivityRef = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
final ImageFetcherActivity activity = mActivityRef.get();
if (activity == null) {
return
}
switch (msg.what) {
case MSG_SHOW_LOADER: {
activity.progressIndicator.setVisibility(View.VISIBLE);
break;
}
case MSG_HIDE_LOADER: {
activity.progressIndicator.setVisibility(View.GONE);
break;
}
case MSG_SHOW_IMAGE: {
activity.progressIndicator.setVisibility(View.GONE);
activity.imageView.setImageBitmap((Bitmap) msg.obj);
break;
}
}
}
}
在使用activity对象时,进行判空操作,以防activity已经被GC回收。这个逻辑解决了内存泄露问题,但引发了另一个问题。如果Activity 已经被销毁,但垃圾回收器还没来得及回收引用,依赖于操作系统运行时的状况,这可能会使你的程序导致潜在的崩溃。修改如下:
static class UIHandler extends Handler {
private final WeakReference<ImageFetcherActivity> mActivityRef;
UIHandler(ImageFetcherActivity activity) {
mActivityRef = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
final ImageFetcherActivity activity = mActivityRef.get();
if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
removeCallbacksAndMessages(null);
return
}
switch (msg.what) {
case MSG_SHOW_LOADER: {
activity.progressIndicator.setVisibility(View.VISIBLE);
break;
}
case MSG_HIDE_LOADER: {
activity.progressIndicator.setVisibility(View.GONE);
break;
}
case MSG_SHOW_IMAGE: {
activity.progressIndicator.setVisibility(View.GONE);
activity.imageView.setImageBitmap((Bitmap) msg.obj);
break;
}
}
}
}
在使用activity引用时,判断一下状态。