这段代码可以避免 Android 处理程序内存泄漏吗?

use*_*746 4 android memory-leaks callback handler

handler1 是泄漏。

我想将handler1代码转换为handler2代码。这可以吗?

这两个代码有什么区别?

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // leaks!
        Handler handler1 = new Handler()
        {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.e("LOG", "Hello~1");
            }
        };

        Handler handler2 = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                Log.e("LOG", "Hello~2");
                return false;
            }
        });

        handler1.postDelayed(new Runnable() {
            @Override
            public void run() { }
        }, 60000);
        handler2.postDelayed(new Runnable() {
            @Override
            public void run() { }
        }, 60000);

        finish();
    }
}
Run Code Online (Sandbox Code Playgroud)

sam*_*cde 7

为什么处理程序 1 会出现泄漏警告?

对于泄漏警告的原因,这篇文章解释得很好。

引自文章

在 Java 中,非静态内部类和匿名类持有对其外部类的隐式引用。另一方面,静态内部类则不然。

所以当你handler1通过匿名类创建时,它会持有对MainActivity实例的引用,MainActiviy不能被垃圾收集。

解决方案

再次引用文章

要解决此问题,请在新文件中对 Handler 进行子类化,或者改用静态内部类。静态内部类不持有对其外部类的隐式引用,因此活动不会泄漏。如果您需要从处理程序内部调用外部活动的方法,请让处理程序持有对活动的 WeakReference,这样您就不会意外泄漏上下文。为了修复实例化匿名 Runnable 类时发生的内存泄漏,我们将变量设为类的静态字段(因为匿名类的静态实例不包含对其外部类的隐式引用):

按照文章,更新您的代码如下:

public class MainActivity extends AppCompatActivity {

    private static class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
             Log.e("LOG", "Hello~1");
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Handler handler1 = new MyHandler();

        handler1.postDelayed(new Runnable() {
            @Override
            public void run() { }
        }, 60000);

        finish();
    }
}
Run Code Online (Sandbox Code Playgroud)

handler2能解决问题吗?

@Michael这个 Handler 类的答案应该是静态的,否则可能会发生泄漏:IncomingHandler 提供了解决方案。

引用@Michael的回答

据我了解,这不会避免潜在的内存泄漏。消息对象持有对 mIncomingHandler 对象的引用,该对象持有对 Handler.Callback 对象的引用,该对象持有对服务对象的引用。只要 Looper 消息队列中有消息,Service 就不会被 GC。但是,除非消息队列中有长时间延迟的消息,否则这不会是一个严重的问题。

在您的情况下,handler2将持有对对象的引用。Handler.Callback由于Handler.Callback是由匿名类创建的,因此它也将持有对MainActiviy实例的引用。所以MainActiviy实例也不能被垃圾收集。