@linux1s1s
2017-01-22T08:03:26.000000Z
字数 2336
阅读 3560
AndroidMemory 2015-04
考虑到下面的代码:
public class SampleActivity extends Activity {private final Handler mLeakyHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// ...}}}
上面这段代码,虽然不是很明显,但是会导致内存泄露,Android Studio会做出下面的提示
In Android, Handler classes should be static or leaks might occur.
为神马会导致内存泄露呢?它又是如何发生的呢?
首先先来梳理一下我们已知的部分知识:
因此为神马会内存泄露?这个比较微妙,为了清晰起见,看下面的代码:
public class SampleActivity extends Activity {private final Handler mLeakyHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// ...}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Post a message and delay its execution for 10 minutes.mLeakyHandler.postDelayed(new Runnable() {@Overridepublic void run() { /* ... */ }}, 1000 * 60 * 10);// Go back to the previous Activity.finish();}}
当SampleActivity生命周期结束的时候,延迟的Message依然会存活10分钟,直到它处理了这个消息,而这个Message持有Handler的引用,而Handler持有外部类SampleActivity的引用,所以GC不会回收SampleActivity,即使它已经生命周期结束很久了,这样便导致了内存泄露。另外注意到弟15行仍然有个匿名内部类Runnable的引用最终也会导致同样内存泄露,那么如何优化上面的代码呢?我们可以尽量采用静态内部类和非匿名类,尤其是非静态内部类或者匿名类具有比外部类更长的生命周期的情况
public class SampleActivity extends Activity {/*** Instances of static inner classes do not hold an implicit* reference to their outer class.*/private static class MyHandler extends Handler {private final WeakReference<SampleActivity> mActivity;public MyHandler(SampleActivity activity) {mActivity = new WeakReference<SampleActivity>(activity);}@Overridepublic void handleMessage(Message msg) {SampleActivity activity = mActivity.get();if (activity != null) {// ...}}}private final MyHandler mHandler = new MyHandler(this);/*** Instances of anonymous classes do not hold an implicit* reference to their outer class when they are "static".*/private static final Runnable sRunnable = new Runnable() {@Overridepublic void run() { /* ... */ }};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Post a message and delay its execution for 10 minutes.mHandler.postDelayed(sRunnable, 1000 * 60 * 10);// Go back to the previous Activity.finish();}}
我们将Handler声明为静态内部类,这样就不会持有外部类的引用,Runnable也一并如此处理。
