반응형

This Handler class should be static or leaks might occur

 

안드로이드에서 Handler 오브젝트는 모든 스레드 반복문에서 참조하는데 어느 한곳에 종속되면 안되기 때문이다.

 

그렇게 되면 가비지 컬렉션이 되지 않아 Memory leak이 계속해서 발생하게 된다.

 

핸들러의 하위 클래스를 만들어서 약참조 시킴으로써 해결 할 수 있다.

 

즉, 사실은 아래와 같은 코드를 쓰면 안된다는 것이다.

 

https://www.crocus.co.kr/1603

 

MainHandler와 ThreadHandler를 통한 통신 예제

메인 핸들러와 스레드 핸들러를 만든 후 서로 메시지를 1초에 한번씩 주고받는 방식을 구현해보았다. 이때 메인은 Looper이 없는 이유가 메인 스레드는 기본적으로 Looper가 실행중인 상태이고 Thread에서만 Loope..

www.crocus.co.kr

package com.example.myhandler;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    static final int THREAD_MSG = 1;
    static final int MAIN_MSG = 2;

    int num = 0;
    TextView textView;
    Handler tHandler;
    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);

            switch(msg.what) {
                case MAIN_MSG:
                    textView.setText("이것은 메인 핸들러!" + num);
                    if(num < 10){
                        num++;
                        tHandler.sendEmptyMessageDelayed(THREAD_MSG, 1000);
                    }
                    break;
            }
        }
    };

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

        textView = findViewById(R.id.text_view);

        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }

    class MyRunnable implements Runnable {
        @Override
        public void run() {
            // 루퍼를 생성시켜 핸들러가 계속 메시지를 수신 할 수 있도록 한다.
            Looper.prepare();
            tHandler = new Handler(){
                @Override
                public void handleMessage(@NonNull Message msg) {
                    super.handleMessage(msg);

                    switch (msg.what) {
                        case THREAD_MSG:
                            mHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    textView.setText("이것은 스레드 핸들러! " + num);
                                    if(num < 10){
                                        num++;
                                        mHandler.sendEmptyMessageDelayed(MAIN_MSG, 1000);
                                    }
                                }
                            });
                            break;
                    }
                }
            };

            // hadler 생성 후 메인으로 메시지를 보낸다.
            mHandler.sendEmptyMessage(MAIN_MSG);
            Looper.loop();
        }
    }
}

 

위와 같은 코드는 결국 두 핸들러 모두 하나에 종속되게 만들었기에 메모리 릭 위험에 빠지게 된다.

 

 

잘못된 방식

package com.example.myhandler;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Handler;
import android.os.Message;

public class MainActivity extends AppCompatActivity {

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);
        }
    };
}

 

 

해결 방법

package com.example.myhandler;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Handler;
import android.os.Message;

import java.lang.ref.WeakReference;

public class MainActivity extends AppCompatActivity {

    private final MyHandler handler = new MyHandler(this);

    private static class MyHandler extends Handler {
        private final WeakReference<MainActivity> weakReference;

        public MyHandler(MainActivity activity){
            this.weakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            // 핸들링 내용 기입
        }
    }
}

 

 

 

반응형