본문 바로가기

Android/Threads on Android

Android Threads example

Android에서 Thread를 다루는 것은 Java SE의 그것과는 조금 다르다.
Android에서 프로그램이 실행되면 main 쓰레드가 먼저 실행되는데, main 쓰레드는 UI Thread라고도 하며, UI를 관리하고 이용자의 이벤트를 받아서 이벤트핸들러 메소드를 호출하는 등의 중요한 부분을 담당하고 있다.
일반 컴퓨터에 비해서 메모리나 성능 등에서 제한을 받는 환경에서 실행되어야 하기 때문에 User 쓰레드가 무분별하게 실행될 경우에는 UI 쓰레드가 느려지고 사용자 인터페이스도 즉각적인 반응을 하기가 어려울 것이다.
그래서 Android에서는 Single Thread Model을 채택하게 되었고, Android UI Toolkit은 다중 쓰레드로부터 안전하지 못한 상태이다. 그러므로 User 쓰레드가 UI에 어떤 변경을 가할 필요가 있다면 반드시 UI Thread에 전달하여 실행될 수 있도록 해야한다.

유저 쓰레드에서 바로 화면의 UI를 갱신하려고 시도하면 오류가 발생한다

UI 쓰레드에 접속하기 위해 다음과 같은 몇가지 방법을 사용한다.

• Activity.runOnUiThread(Runnable)
• View.post(Runnable)
• View.postDelayed(Runnable, long)
• Handler

위에서 3번째 방법까지는 서로 유사한 점이 있다. 쓰레드가 실행할 코드에 해당하는 Runnable 객체를 전달한다는 공통점이 있다.
마지막 네번째 방법은 Runnable이 아니라 일반 User Thread 객체를 실행하고 User Thread 내에서 직접 UI를 제어하는 것이 아니라 Handler객체를 경유하여 UI Thread에 연결되는 방법이고 가장 유연한 쓰레드 운용법으로 알려져 있다.

다음은 User 쓰레드와 Handler를 사용하여 ProgressBar를 설정하는 예제이다.
User 쓰레드에서 Handler에게 Message를 보내면 Handler의 handleMessage()메소드가 실행되어 UI 쓰레드와 연결되는 내용이다.

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;

public class HandlerThreadActivity extends Activity {
   ProgressBar bar;
   @Override
   public void onCreate(Bundle icicle) {
      super.onCreate(icicle);
      setContentView(R.layout.main);
      bar=(ProgressBar)findViewById(R.id.progress);
   }
   public void onStart() {
      super.onStart();
      bar.setProgress(0);
      new Thread(new Runnable() {
         public void run() {
            try {
               for (int i=0;i<50;i++) {
                  Thread.sleep(1000);
                  handler.sendEmptyMessage(0);
               }
            }
            catch (Throwable t) {
            }
         }
      }).start();
   }
   Handler handler=new Handler() {
      @Override
      public void handleMessage(Message msg) {
          bar.incrementProgressBy(2);
       }
   };
}