Android2010.09.04 18:33

메시지는 즉시 호출되는 메소드와는 달리 스레드간의 신호이므로 보낸다고 해서 바로 바로 처리되는 것은 아니다.
어딘가에 쌓아놓고 순서대로 처리하게 되는데 이렇게 전달되는 메시지를 차곡차곡 쌓아놓는 곳이 메시지 큐(Message Queue)이다.

큐에서 메시지를 꺼내서 핸들러로 전달하는 역할을 하는게 바로 루퍼(Looper)이다.
루퍼는 무한히 실행되는 메시지 루프를 통해 큐에 메시지가 들어오는지 감시하며 들어온 메시지를 처리할 핸들러를 찾아 handleMessage 메소드를 호출한다.
UI를 관리하는 메인스레드는 기본적으로 루퍼를 가지고 이미 동작하므로 별다른 신경 쓸 필요가 없다.
루퍼를 직접 프로그래밍을 해야하는 경우는 작업 스레드가 메시지를 받아야 할 때이다. 작업 스레드는 디폴트로 루퍼가 없기 때문에 직접 생성하고 실행시켜야 메시지를 받을 수 있다.

다음은 루프를 새성하고 실행하는 메소드이다.
static void prepare()
static void loop()
void quit()

prepare는 현재 스레드를 위한 루퍼를 준비한다.
loop메소드는 큐에서 메시지를 꺼내 핸들러로 전달하는 루프를 실행한다. 이 루프는 quit메소드가 호출되어 루프를 종료할 때까지 무한 반복된다.
루프는 스레드별로 하나씩 생성된다.
다음은 스레드에 관련된 루퍼를 구하는 메소드이다.
Thread getThread()
static Looper getMainLooper()
static Looper myLooper()

getThread메소드는 루퍼와 연결된 스레드를 구한다.
반대로 스레드에서 루퍼 객체를 구하고 싶을 때는 getMainLooper, myLooper 메소드를 호출하는데 getMainLooper메소드는 응용프로그램의 주 스레드의 루퍼를 구하고 myLooper메소드는 현재 스레드의 루퍼를 구한다.

 LooperTest.java
 public class LooperTest extends Activity {
     int mMainValue = 0;
     TextView mMainText;
     TextView mBackText;
     EditText mNumEdit;
     CalcThread mThread;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        mMainText = (TextView)findViewById(R.id.mainvalue);
        mBackText = (TextView)findViewById(R.id.backvalue);
        mNumEdit = (EditText)findViewById(R.id.number);
       
        Button btn = (Button)findViewById(R.id.increase);
        btn.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
               mMainValue++;
               mMainText.setText("MainValue : " + mMainValue);
            }
        });

        btn = (Button)findViewById(R.id.root);
        btn.setOnClickListener(new Button.OnClickListener() {
           public void onClick(View v) {
               Message msg = Message.obtain();
               msg.what = 0;
               msg.arg1 = Integer.parseInt(mNumEdit.getText().toString());
               mThread.mBackHandler.sendMessage(msg);
           }
        });
        
        btn = (Button)findViewById(R.id.square);
        btn.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                Message msg = Message.obtain();
                msg.what = 1;
                msg.arg1 = Integer.parseInt(mNumEdit.getText().toString());
                mThread.mBackHandler.sendMessage(msg);
            }
        }); 
                
        mThread = new CalcThread(mHandler);
        mThread.setDaemon(true);
        mThread.start();
    }
    
    // 서브 스레드로부터 오는 메시지를 받아서 처리.
    Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
           switch(msg.what) {
           case 0 :
              mBackText.setText("Root Result : " + msg.arg1);
              break;
           case 1 :
              mBackText.setText("Square Result : " + ((Double)msg.obj).doubleValue());
              break;
           }
       }
    };
   
}

 CalcThread.java
 public class CalcThread extends Thread {
     Handler mMainHandler;
 
     // 메인스레드에게 메시지를 전달하기 위해 생성자로 handler를 받는다.
     CalcThread(Handler handler) {
         this.mMainHandler = handler;
     }
 
     public void run() {
          // 서브스레드는 기본적으로 메시지를 받아서 처리할 수 있는 루퍼가 없기 때문에 생성, 시작해주어야 한다.
          Looper.prepare();
          Looper.loop();

     }
 
     public Handler mBackHandler = new Handler() {
         public void handleMessage(Message msg) {
              Message retMsg = Message.obtain();
              switch(msg.what) {
              case 0 :
                  try {Thread.sleep(1000); } catch(InterruptedException e) {;}
                  retMsg.what = 0;
                  retMsg.arg1 = msg.arg1 * msg.arg1;
                  break;
              case 1 :
                  try {Thread.sleep(1000); } catch(InterruptedException e) {;}
                  retMsg.what = 1;
                  retMsg.obj = new Double(Math.sqrt((double)msg.arg1));
                  break;
              }
              mMainHandler.sendMessage(retMsg); // 메인스레드로 메시지 전송
        }
    };
}

위 예제 소스의 흐름을 간략하게 설명하자면 메인스레드에 있는 버튼을 클릭하면 작업스레드(CalcThread)로 sendMessage메소드를 통해 메시지를 보내게 된다.
작업스레드(CalcThread)는 해당 메시지를 받아서 처리한 후 메인스레드(Activity)로 다시 sendMessage를 호출해 메시지를 보낸다.
메인스레드(Activity)는 메시지를 받아 화면에 보여주게 된다.



저작자 표시
신고

'Android' 카테고리의 다른 글

43. ANR  (0) 2010.09.05
42. 스레드 - 작업스케줄링  (0) 2010.09.04
41. 스레드 - 루퍼  (0) 2010.09.04
40. 스레드  (1) 2010.09.04
39. 대화상자 - 질문하기  (0) 2010.08.30
38. 대화상자  (0) 2010.08.29
Posted by 밥팅우기

티스토리 툴바