問題原因及解決方案
項目中有不少使用Handler的地方,有時候為了方便直接Handler handler = new Handler()這種寫法,但是在Java中,非靜態(tài)的匿名InnerClass會持有一個OuterClass的隱式引用,而靜態(tài)內(nèi)部類則不會。在Android studio上會提示你如下的警告信息:
This Handler class should be static or leaks might occur

屏幕快照 2018-01-10 下午3.09.36.png
對此,Google的Romain Guy給出了建議

0-2.png
所以針對Romain Guy的建議,圖1的的問題解決方案如下:
private static class BlurHandler extends Handler {
private final WeakReference<BlurController> mTarget;
public BlurHandler(BlurController controller) {
mTarget = new WeakReference<BlurController>(controller);
}
@Override
public void handleMessage(Message msg) {
BlurController controller = mTarget.get();
if (controller != null) {
Bitmap bitmap = (Bitmap) msg.obj;
if (bitmap != null && !bitmap.isRecycled()) {
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap,
bitmap.getWidth() / SCALE_RATIO,
bitmap.getHeight() / SCALE_RATIO,
false);
Bitmap blurBitmap = FastBlurUtil.doBlur(scaledBitmap, BLUR_RADIUS, true);
if (blurBitmap != null) {
controller.imgBigBg.setImageBitmap(blurBitmap);
}
}
}
}
}
ps:BlurHandler在BlurController類中,注意Romain Guy提到的OuterClass可以是任何類,可以是View,Activity,或者XXUtils,我這里就是BlurController。
給出了解決方案,會有到底是如何發(fā)生的內(nèi)存泄漏?
public class SampleActivity extends Activity {
private final Handler mLeakyHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Post a message and delay its execution for 10 minutes.
mLeakyHandler.postDelayed(new Runnable() {
@Override
public void run() { /* ... */ }
}, 1000 * 60 * 10);
// Go back to the previous Activity.
finish();
}
}
當(dāng)activity被finish掉后,delayed message會在主線程的消息隊列中存在10分鐘后才會被執(zhí)行,這個Message會持有一個SampleActivity中Handler的引用,而這個Handler也會持有一個SampleActivity的隱式引用,這個引用會一直存在直到message被執(zhí)行,這樣會防止Activity的context被垃圾回收,但同時也會泄露application的資源。
小結(jié)
- 如果使用InnerClass,請設(shè)置為static
- 對外部類持有個WeakReference