問題原因及解決方案
項(xiàng)目中有不少使用Handler的地方,有時(shí)候?yàn)榱朔奖阒苯親andler handler = new Handler()這種寫法,但是在Java中,非靜態(tài)的匿名InnerClass會(huì)持有一個(gè)OuterClass的隱式引用,而靜態(tài)內(nèi)部類則不會(huì)。在Android studio上會(huì)提示你如下的警告信息:
This Handler class should be static or leaks might occur
對(duì)此,Google的Romain Guy給出了建議
所以針對(duì)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。
給出了解決方案,會(huì)有到底是如何發(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會(huì)在主線程的消息隊(duì)列中存在10分鐘后才會(huì)被執(zhí)行,這個(gè)Message會(huì)持有一個(gè)SampleActivity中Handler的引用,而這個(gè)Handler也會(huì)持有一個(gè)SampleActivity的隱式引用,這個(gè)引用會(huì)一直存在直到message被執(zhí)行,這樣會(huì)防止Activity的context被垃圾回收,但同時(shí)也會(huì)泄露application的資源。
小結(jié)
- 如果使用InnerClass,請(qǐng)?jiān)O(shè)置為static
- 對(duì)外部類持有個(gè)WeakReference