[안드로이드] 스레드(Thread)와 핸들러(Handler)

김영훈·2020년 4월 14일
2
post-thumbnail

스레드

스레드(Thread)란 동시 작업을 위한 하나의 실행 단위입니다.
앱을 실행하면 메인 스레드라는 하나의 스레드가 시작되는데
이 메인 스레드는 앱의 기본 실행을 담당합니다.

만약 사용자가 필요에 따라 직접 새로운 스레드가 만들 경우에는
이미지등의 파일과 ui 리소스에 접근이 필요할 경우가 발생하고
메인 스레드가 아닌 스레드가 리소스를 직접 접근하게 되면 문제가 발생합니다.

예를 들어 입력 상자가 있을 때 메인 스레드에서 접근하고 관리하게 되고
만약 새로 만들어진 스레드에서 입력상자에 Text를 설정하든 접근을 하게되면 데드락이 발생합니다.

왜냐하면 동시에 어떤 하나의 리소스에 접근을 했을때 시스템에서 어떤 스레드의 작업을 먼저 처리할지 모르기 때문에 멈추게 됩니다.

핸들러

위의 문제 때문에 메인 외 다른 스레드들은 별도의 제어를 통해 UI부분을 다뤄야합니다.
따라서 메인 스레드가 아닌 스레드에서는 UI 부분을 다룰때 핸들러를 통해 접근이 이뤄집니다.

핸들러는 각각의 스레드 안에 만들어질 수 있고 다른 스레드에서 요청하는 정보를 메세지 큐(Message Queue)를 통해 순서대로 실행시켜 줄 수 있기 때문에 리소스에 대한 동시 접근의 문제를 해결해 줍니다.

예를 들어 메인 스레드 안에 핸들러를 만들어놓으면
다른 스레드에서는 특정 작업을 먼저 핸들러 쪽에 요청합니다.

핸들러는 메시지 큐(Message Queue)를 통해 순차적으로 메인 스레드에서 처리할 메시지를 전달하는 역할을 담당합니다.

핸들러를 사용할 때 필요한 세 가지 단계

  • obtainMessage() : 호출의 결과로 메시지 객체를 리턴 받게함
  • sendMessage() : Message Queue 에 넣음
  • handleMessage() : 메소드에 정의된 기능이 수행됨

스레드에서 핸들러로 메시지를 보내려면 Message 객체를 사용합니다.

Message 객체를 obtainMessage 메소드로 참조한 후 sendMessage 메시지를 이용해 핸들러로 보내면 handleMessage 메소드가 자동으로 호출되기 때문에 전달된 Message 객체를 처리할 수 있습니다.

이 때 handleMessage 메소드는 메인 스레드에서 실행됩니다.

예제

public class MainActivity extends AppCompatActivity {

    TextView textView;
    ValueHandler handler = new ValueHandler();

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

        textView = (TextView) findViewById(R.id.textView);

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                BackgroundThread thread = new BackgroundThread();
                thread.start();
            }
        });

        Button button2 = (Button) findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { }
        });
    }

    // 스레드 클래스 생성
    class BackgroundThread extends Thread {
        int value = 0;
        boolean running = false;
        public void run() {
            running = true;
            while(running) {
                value += 1;
                Message message = handler.obtainMessage();
                Bundle bundle = new Bundle();
                bundle.putInt("value",value);
                message.setData(bundle);
                handler.sendMessage(message);

                try {
                    Thread.sleep(1000);
                } catch (Exception e) {}
            }
        }
    }

    class ValueHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);

            Bundle bundle = msg.getData();
            int value = bundle.getInt("value");
            textView.setText("현재 값 : " + value);
        }
    }
}

스레드와 핸들러를 사용해 1초 마다 1씩 증가하는 값을 출력

0개의 댓글