티스토리 뷰

프로그램/안드로이드 강좌

쓰레드-1

서.라.연 2012. 8. 15. 12:34


이 자료들은 팁스소프트에서 제공하는 [ 알짜배기 ] 프로그램을 이용하면 더 편리하게 볼수 있습니다.
* 알짜배기 프로그램 받기 - http://www.tipssoft.com/bulletin/tb.php/QnA/8406
* 안드로이드 강좌 목록 - http://www.tipssoft.com/bulletin/tb.php/old_bbs/501
일반적으로 안드로이드 시스템의 응용 프로그램은 하나의 실행 흐름을 가집니다. 따라서 오랜 수행시간을
필요로하는 작업을 하면 사용자의 다른 요청을 처리할 수 없게 됩니다. 심지어 해당 프로그램을 터치해도
아무런 반응을 하지 않고, 프로그램이 응답없음 상태에 빠지면서 수초 후에 안드로이드 시스템에서는
프로그램의 종료여부를 묻기도 합니다.
실제로는 다른 작업을 하는 중이어서 응답을 할 수 없는 것이지만 시스템이나 사용자는 그것을 알 수
없어서 생기는 문제입니다. 따라서 이런 문제를 해결하기 위해서는 또다른 실행 흐름을 추가하여 해결
해야합니다. 이 강좌는 스레드(Thread)라는 실행 흐름에 대한 설명과 추가하는 방법에 대한 내용입니다.
1. 스레드 (Thread) 란?
스레드를 설명하기 전에 이 글에서 언급되는 용어들에 대하여 알아보도록 하겠습니다.
- 응용프로그램 ( Application )
사용자에게 특정 서비스를 제공할 목적으로 구현된 응용 프로그램을 말합니다.

- 컴포넌트 ( component )
어플리케이션을 구성하는 기능별 요소로써 안드로이드 시스템에서는 Activities, Services,
Content Providers, Broadcast Receivers 라는 네가지 유형의 컴포넌트 있습니다.

- 프로세스 ( process )
응용 프로그램이 메모리에 로드되어 실행가능한 상태로 재구성 된 것을 말합니다.
즉, 응용프로그램이 실행되면 프로세스가 된다고 생각하면 됩니다. 그런데 응용프로그램은
여러개의 컴포넌트들로 구성되어 있기때문에 컴포넌트가 실행되어도 프로그램이 실행되는 것과
동일합니다. 하지만 안드로이드 시스템은 동일한 프로그램에 대해서 하나의 프로세스로 유지하기
때문에 컴포넌트가 실행된다고해서 반드시 프로세스가 생성되지는 않습니다.
일반적으로 스레드는 프로세스 내에서 실행되고 있는 흐름을 말합니다. 기본적으로 프로세스가
생성되면 하나의 스레드가 같이 생성되는데 이것을 메인 스레드라고 합니다. 이 스레드는 동일
프로세스 내에 실행되는 모든 컴포넌트를 직접 실행하며 UI 에서 수행되는 그리기 작업이나
컨트롤들에 대한 모든 이벤트들을 직접 처리합니다. 이와 같은 특징때문에 메인 스레드를
UI 스레드 라고도 합니다.
이처럼 메인 스레드는 프로세스 내에서 기본적으로 많은 일을 처리하기때문에 많은 리소스를 필요로
하거나 반복적인 작업을 오랫동안 지속해야하는 경우에는 어떤 이벤트나 작업도 처리하지 못하는
응용프로그램 응답없음 상태에 종종 빠지기도 합니다.
그래서 프로그램에 부하를 주는 작업을 하는 경우에는 메인 스레드가 아닌 다른 스레드에서 해당
작업을 수행할 수 있도록 별도의 스레드를 생성하는 것을 권장하고 있습니다. 하지만 이렇게 스레드를
추가해서 사용하게되면 스레드간 충돌에 대해서 안드로이드 시스템이 안전을 보장하지 않기 때문에
프로그래머는 아래와 같은 2가지 사항을 주의해야 합니다.
- 메인 스레드에 긴 작업 시간을 요구하는 작업을 시켜서는 안된다. 메인 스레드가 반응하지 못하는
상태에 빠지면 해당 프로그램은 응답없음 상태를 피할 수 없다.
- 추가된 스레드에서는 UI 관련 함수(Android UI toolkit)를 직접 사용하면 안된다.
반드시 메인 스레드에 원하는 작업의 수행을 요청해야 한다.
2. 스레드 생성하기
응용프로그램에서 스레드를 추가하여 사용한다는 것은 내가 원하는 루틴이 메인 스레드와 동시에
수행된다는 의미입니다. 스레드를 추가할 때에는 Thread 클래스를 사용하는데 이 클래스 내부에는
사용자가 원하는 작업을 미리 정의해 둘 수 없기때문에 Runnable 이라는 인터페이스를 사용하여
해당 인터페이스의 run 메소드를 통해 작업을 정의하도록 하고 있습니다.
Runnable 인터페이스는 유일하게 run 메소드만 정의하여 사용하도록 하고 있으며 Thread 클래스
또한 이 인터페이스를 가지고 있습니다. 그래서 Thread 클래스를 상속받는 사용자 정의 클래스를
만들거나 Thread 객체를 생성하면서 클래스 내의 run 메소드를 직접 재정의하기도 하고, Thread
객체를 생성할 때 생성자에 run 메소드가 정의된 Runnable 객체를 인자로 넘겨주기도 합니다.
지금까지 설명한 스레드를 추가하는 방법에 대하여 자세하게 알아보도록 하겠습니다.
( Thread 클래스를 상속받는 클래스를 만들어서 run 메소드를 정의하는 방법은 제외하였습니다. )
2.1 Runnable 객체를 멤버 변수로 선언하여 Thread 에 설정하기
Runnable 객체를 멤버 변수로 선언하고, run 메소드를 미리 정의해두어서 Thread 객체를
생성할 때 객체 생성자에 선언해둔 Runnable 멤버 변수를 인자로 넘겨줍니다.
public class ExamThreadAppActivity extends Activity
{
// Runnable 객체를 생성하고 run 메소드 정의한다.
Private Runnable m_run_code = new Runnable() {
public void run() {
// .. 추가된 Thread가 수행할 루틴
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Thread 객체를 생성하고 생성자에 Runnable 객체를 넘겨주어
// 해당 스레드에서 m_run_code 에 정의된 run 메소드를 수행할 수 있도록 한다.
Thread my_thread = new Thread(m_run_code);
}
}
2.2 Thread 객체 생성자에 Runnable 인터페이스를 직접 생성하기
Runnable 인터페이스를 따로 선언해두지 않고, Thread 객체를 생성할 때 new 키워드를 이용하여
생성하고, run 메소드를 바로 정의하는 방법입니다.
public class ExamThreadAppActivity extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Thread 객체를 생성하고 run 메소드를 정의한 Runnable 객체를 생성하여 생성자로
// 넘겨주어 해당 스레드에서 run 메소드를 수행할 수 있도록 한다.
Thread my_thread = new Thread(new Runnable() {
public void run() {
// .. 추가된 Thread가 수행할 루틴
}
});
}
}
2.3 Thread 클래스에 정의된 run 메소드 재정의하기
Thread 클래스도 Runnable 인터페이스를 포함하고 있기 때문에 Thread 클래스의 run 메소드를
직접 재정의할 수 있습니다. Thread 객체를 생성하고 이어서 바로 run 메소드를 재정의 합니다.
public class ExamThreadAppActivity extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Thread 객체를 생성하면서, Thread 클래스 내의 run 메소드를 재정의한다.
Thread my_thread = new Thread() {
public void run() {
// .. 추가된 Thread가 수행할 루틴
}
};
}
}
2.4 메인 클래스에 Runnable 인터페이스를 추가하여 run 메소드 정의하기
Thread 객체를 생성할 클래스에 implements 키워드로 Runnable 인터페이스를 추가하여 run
메소드를 해당 클래스에서 재정의합니다.
// 이 클래스에서 Runnable 인터페이스의 run 메소드를 재정의 할 수 있도록 한다.
public class ExamThreadAppActivity extends Activity implements Runnable
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Thread 를 생성하고, 생성자에 이 클래스를 넘겨준다.
// 이 클래스에는 Runnable 인터페이스가 포함되어 있어서 Thread 생성자 내부에는
// 아래의 run 메소드가 정의된 Runnable 인터페이스로 받게 된다.
Thread my_thread = new Thread(this);
}
// my_thread 스레드가 수행하게 되는 run 메소드
public void run()
{
// .. 추가된 Thread가 수행할 루틴
}
}
위와 같은 여러가지 방법으로 추가된 스레드는 Thread 클래스의 start 메소드를 이용하여 run 메소드에
정의된 루틴들을 실행하도록 할 수 있습니다.
Thread my_thread = new Thread(...);
my_thread.start();
3. 생성된 스레드에서 UI 관련 작업하기
앞에서 설명했듯이 응용프로그램에서 UI 에 관련된 작업은 메인 스레드가 처리합니다. 메인 스레드가
아닌 추가된 스레드에서 UI 에 관련된 작업을 직접 수행하는 것은 메인 스레드와의 충돌 위험성 등이
존재하여 안전하지 않기때문에 다른 스레드에서 해당 작업을 수행하고자 할 때에는 메인 스레드에서
대신 처리할 수 있도록 처리 작업을 넘겨주기도 합니다.
추가된 스레드에서 메인 스레드로 작업을 넘기는 방법은 View 클래스의 post 메소드를 사용하는
방법과 Handler 클래스의 post 메소드를 사용하는 방법이 있으며 이번 강좌에서는 View 클래스의
post 메소드를 사용하는 방법만 언급하도록 하겠습니다.
다른 스레드에서 메인 스레드로 작업을 넘기는 것은 스레드가 수행할 루틴을 Runnable 인터페이스의
run 메소드에 정의하여 Thread 객체에 넘기는 것과 동일하게 생각하시면 됩니다. 즉, post 메소드도
인자로 Runnable 객체를 받아서 해당 객체에 정의된 run 메소드를 메인 스레드가 수행하도록 하기
때문입니다.
그렇기때문에 2.1 이나 2.2 와 동일한 방법으로 메인 스레드가 처리했으면 하는 작업들을 run 메소드에
구성하면 되고, post 메소드는 대부분 컨트롤의 상위 클래스인 View 클래스의 메소드이므로 컨트롤
객체를 얻어서 객체명.post(Runnable 객체) 로 호출하면 됩니다.
예를 들어, 네트워크 프로그램을 만든다고 가정하면 데이터를 수신하는 부분이 긴 시간을 요구하는
작업이 될 수 있기때문에 메인 스레드가 응답없음 상태가 될 수 있습니다. 이러한 문제를 해결하기
위해서 스레드를 추가하여 데이터를 수신하는 부분을 해당 스레드가 수행하도록 하면 됩니다.
하지만 수신된 데이터를 텍스트뷰와 같은 컨트롤에 출력하고 싶다면 데이터를 수신한 스레드가
메인 스레드가 아니기 때문에 직접 UI 함수를 사용하면 충돌하여 문제가 발생합니다. 이런 경우
아래와 같이 post 메소드를 사용하여 메인 스레드로 작업 수행을 요청해서 해결할 수 있습니다.
( 아래의 코드는 추가된 스레드의 run 메소드에서 메인 스레드가 처리해야할 코드를 VIew 의 하위
클래스인 TextView 객체를 이용해서 전달하는 예제입니다. )
public class ExamThreadAppActivity extends Activity implements Runnable
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Thread my_thread = new Thread(this);
my_thread.start();
}
public void run()
{
// 메인 스레드에서 수행하고자 하는 루틴을 run 메소드에 정의하여 Runnable 객체를 선언한다.
Runnable main_run = new Runnable() {
public void run()
{
// 메인 스레드가 처리해야할 루틴...
}
};
// TextView 클래스는 View 클래스의 하위 클래스이므로 post 메소드 가지고 있다
TextView tv = (TextView) findViewById(R.id.id_tv);
// 메인 스레드에게 main_run 객체의 run 메소드에 정의된 루틴을 수행하도록 전달한다.
tv.post(main_run);
}
}


'프로그램 > 안드로이드 강좌' 카테고리의 다른 글

소켓통신의 활용 - MFC 서버와 통신하기  (0) 2012.08.15
스트림의 이해  (0) 2012.08.15
리스트뷰 사용하기2  (0) 2012.08.15
리스트뷰 사용하기 1  (0) 2012.08.15
Edittext 사용하기  (0) 2012.08.15
댓글