티스토리 뷰

안드로이드에서 각 스레드간 통신하는 방법을 알아 보도록 하자.

안드로이드 에서 하나의 스레드가 시작되면 이 스레드는 Message Queue, Looper, Handler 를 각각 하나씩 가지고 있는다.

Message Queue 란?

외부 스레드로 부터 핸들러를 통하여 받은 Message 혹은 Task(Runnable 인터페이스를 구현한 오브젝트)를 저장하는 역할을 한다.

그럼 Message란? 

메세지란 임이의 Object 데이터와 설명을 포함한 메세지를 정의한 하나의 오브젝트이다.
메세지 오브젝트를 생성하기 위해서는 Message 클래스의 Public 생성자를 사용 할 수 있지만 가장 좋은 방법은 Message.obtain()혹은 Handler.obtainMessage() 정적 함수를 호출하여 오브젝트를 얻는 방법이다. 이 함수들은 핸들러 오브젝트를 재사용 시 Pool에서 꺼내올 수 있도록 디자인 되어 있다. 이런 처리는 어플리케이션의 퍼포먼스를 증가 할 수 있다.

아래는 메세지큐에 메세지를 전달하는 몇가지 옵션이다.

Message Queue 에 메세지를 전달하는 몇가지 옵션.
sendMessage(): 메세지 큐에 메세지를 바로 집어 넣는다.
sendMessageAtFrontOfQueue(): 메세지를 큐의 맨 앞에 집어 넣는다.
sendMessageAtTime(): 정해진 시간에 메세지를 큐에 집어 넣는다.
sendMessageDelayed(): 정해진 시간 후에 메세지를 집어 넣는다.
sendEmptyMessage(): 빈 메세지 오브젝트를 집어 넣는다. 용도는 obtainMessage()스탭을 피할 때 사용한다.


Looper 란?

루퍼는 해당 스레드의 메세지 큐에서 메세지를 순차적으로 꺼내서 핸들러에게 전달하는 역할을 한다. 핸들러는 루퍼로 부터 받은 Message 혹은 Task(Runnable Object)를 수행 한다.


Handler 란?

핸들러는 두가지 기능이 있다.
첫번째: 루퍼에게서 받은 메세지 혹은 Task를 일정한 시간에 수행하는 기능을 한다.
두번째: 외부 스레드로 부터 받은 메세지를 핸들러를 통하여 Message Queue 에 집어 넣는 역할을 한다.

Handler 오브젝트를 생성하면 이 오브젝트는 자동으로 자기를 만든 스레드 혹은 Message Queue 와 연결된다. 보통 스레드당 하나의 핸들러만 필요하며 수동으로 등록 시킬 필요가 없다.

Handler 로 할수 있는건?
나의 Background Thread 일정한 작업을 수행 하면서, Activity의 UI 스레드와 통신할 수 있다.
예를 들어 백그라운드 스레드에서 다운로드 작업을 하며 다운로드 진행상황을 핸들러를 통하여 메인 스레드에있는 프로그레스바를 제어 할 수 있다.

그럼 메세지를 전달 하기 위하여 어떻게 하면 통신하고자 하는 스레드의 핸들러 주소를 알 수 있을까? 아래 두가지 예제를 통하여 설명한다.
1. 첫번째 예제: 다른 스레드에 메세지를 전달 하는 방법.
2.두번째 예제: 다른 스레드에 Runnable 오브젝트를 전달하는 방법.

첫번째 예제
스레드 A와 B가 있다고 가정하자. 스레드 A는 UI 스레드고,  스레드 B에서 작업이 끝난후 스레드 A에 UI 수정 요청을 한다고 가정하자...

public class A extends AppCompatActivity {

    //해당 스레드의 핸들러 주소를 저장하기 위한 변수 선언.
    Handler handler;

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

        //스레드 작업이 끝나면 업데이트 할 View 오브젝트의 주소를 가져온다.
        textView = (TextView) findViewById(R.id.text_view);

        //핸들러를 만든다.
        //현재 글래스 A에서 핸들러를 만들었음으로 이 핸들러는 자동으로 현재 스레드 및
        //메세지큐와 연결된다. 즉 이 핸들러 주소를 통하여 현재 스레드의 메세지 큐에
        //메세지를 전달 할 수 있다. 전달된 메세지는 이 스레드의 Looper을 통하여
        //핸들러의 handleMessage콜백함수에 전달되게 된다.

        handler = new Handler()
        {
            //Looper는 메세지큐에 메세지가 있으면 그 메세지를 꺼내서 핸들러에게
            //전달하며 핸덜리의 아래 콜백 메소드를 호출하게 된다.
            @Override
            public void handleMessage(Message msg) {
                //전달 받은 Message 오브젝트를 가지고 관련된 작업을 수행 할 수 있다.
                //예를 들어 textView의 텍스트를 업데이트 한다든가...  
                //이번예제 에서는 msg의 arg1에 1을 넣었음으로
                //msg.arg1을 통하여 숫자 1을 얻을 수 있다.
            }
        };

        //현재스레드와 통신할 스레드 B를 실행한다.
        //이제 b스레드가 작업을 수행하면서 스레드 A 로 메제지를 보내는 방법은
        //아래 코드를 보면 알 수 있다.
        Thread b = new Thread(new B());
        b.start();
    }

    //스레드 A와 통신할 스레드 B 클래스
    class B implements Runnable {

        @Override
        public void run() {
            //임이의 작업을 수행한다.
            //시간이 걸리는 작업: 예를 들면 인터넷에서 이미지를 다운로드...

            //작업이 끝나면 스레드 A로 보낼 메세지를 만든다.
            Message message = Message.obtain();
            //만든 메세지에 전달할 데이터를 집어 넣는다.
            //메세지 오브젝트에는 여러종류의 데이터를 넣을 수 있다.
            //arg1, arg2:주로 간단한 연산처리에 필요한 Integer value를 넣을 때 사용.
            //obj:우리가 만든 오브젝트를 전달할때 사용, 받는 쪽에서 반드시 해당 타입으로 캐스팅해야 한다.
            //아래 예제에서는 그냥 단순한 숫자 1을 arg1에 넣었다.
            message.arg1 = 1;

            //메세지를 만들었으면 이젠 핸들러를 통하여 보내기만 하면된다. 그러면 메세지를 받은
            //스레드의 루퍼가 메세지를 꺼내서, 핸들러의 handleMessage를 호출하면서 메세지를 함께
            //전달하게 된다.
            //이번예제에서는 스레드 B 클래스를 스레드 A 클래스의 내부 클래스로 선언하였음으로
            //직접 클래스 B에서 직접 handler를 참조 할 수 있다.
            //만약 B가 외부 클래스로 선언되어 잇으면 B 오브젝트를 만들때 반드시 handler를 전달 해
            //줘야하며 B 오브젝트는 받은 핸들러를 나중의 사용을 위하여 저장해 둬야 한다.
            handler.sendMessage(message);

        }
    }




댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함