一、Handler 和 Runnable 都有定时器的功能,当它们作为非静态内部类的时候,同样会持有外部类的引用,如果它们的内部有延迟操作,在延迟操作还没有发生的时候,销毁了外部类,那么外部类对象无法回收,从而造成内存泄漏。
假设MianActivity里面有个Handler的10秒延时操作:
Handler 和 Runnable 作为匿名内部类,都会持有 MainActivity 的引用,而它们内部有一个 10 秒钟的定时器,如果在打开 MainActivity 的 10 秒内关闭了 MainActivity,那么由于 Handler 和 Runnable 的生命周期比 MainActivity 长,会导致 MainActivity 无法被回收,从而造成内存泄漏。
二、应该如何避免内存泄漏呢?
一般套路就是把 Handler 和 Runnable 定义为静态内部类,这样它们就不再持有 MainActivity 的引用了,从而避免了内存泄漏:
public class MainActivity extends AppCompatActivity {
private Handler handler; private Runnable runnable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handler = new TestHandler(); runnable = new TestRunnable(); handler.postDelayed(runnable, 10 * 1000); } private static class TestHandler extends Handler { } private static class TestRunnable implements Runnable { @Override public void run() { Log.d(TAG, "run: "); } } }private static final String TAG = "MainActivity";
还有一种特殊情况,如果 Handler 或者 Runnable 中持有 Context 对象,那么即使使用静态内部类,还是会发生内存泄漏,这种情况可以使用弱引用的方式来引用 Context 来避免内存泄漏@Override protected void onDestroy() { super.onDestroy(); handler.removeCallbacks(runnable); }
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private Handler handler; private Runnable runnable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handler = new TestHandler(new WeakReference<Context>(this)); runnable = new TestRunnable(); handler.postDelayed(runnable, 10 * 1000); } private static class TestHandler extends Handler { private Context context; private TestHandler(WeakReference<Context> weakContext) { context = weakContext.get(); } } private static class TestRunnable implements Runnable { @Override public void run() { Log.d(TAG, "run: "); } } }