Может ли этот код избежать утечки памяти обработчиком Android? - PullRequest
0 голосов
/ 12 сентября 2018

handler1 - это утечка.

Я хочу преобразовать код handler1 в код handler2.Это нормально?

В чем разница между двумя кодами?

открытый класс MainActivity расширяет 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();
}

}

1 Ответ

0 голосов
/ 12 сентября 2018

Почему предупреждение об утечке для обработчика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();
    }
}

Может ли handler2 решить проблему?

Ответ от @Michael Этот класс Handler должен быть статическим или иметь утечкиможет произойти: IncomingHandler предоставляет решение.

Цитата из ответа @Michael

Насколько я понимаю, это не избежит потенциальной утечки памяти.Объекты сообщения содержат ссылку на объект mIncomingHandler, который содержит ссылку на объект Handler.Callback, который содержит ссылку на объект Service.Пока в очереди сообщений Looper есть сообщения, Служба не будет GC.Однако это не будет серьезной проблемой, если у вас нет сообщений с длительной задержкой в ​​очереди сообщений.

В вашем случае handler2 будет содержать ссылку на Handler.Callback object.And начиная с Handler.Callback создается анонимным классом, следовательно, он также будет содержать ссылку на экземпляр MainActiviy.Так что MainActiviy экземпляр также не может быть собран мусором.

...