자바의 스레드 개념에 대한 기본적인 이해가 있는 개발자를 대상으로, 본문에서는 안드로이드 환경에서의 스레드 처리 메커니즘에 대해 심도 있게 다루고자 합니다. 프로세스와 스레드의 차이점에 대한 설명은 생략하며, 관심 있는 개발자는 별도로 학습할 수 있습니다. 안드로이드 앱 개발 시 네트워크 작업과 같은 시간이 소요되는 작업은 반드시 백그라운드 스레드에서 처리해야 하며, 이후 결과는 메인 스레드로 전달하여 UI를 업데이트해야 합니다.
안드로이드 4.0 버전부터는 보안 강화를 위해 네트워크 작업을 별도의 스레드에서 처리하도록 요구하고 있습니다. 이는 네트워크 접속이 UI 스레드를 차단할 수 있기 때문입니다. 아래 예제는 백그라운드 스레드에서 UI를 직접 업데이트하려 할 발생하는 문제를 보여줍니다.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
uiElement = (TextView) findViewById(R.id.display_text);
/*
* 백그라운드 스레드에서 UI 업데이트 시도
*/
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000); // 네트워크 작업 시뮬레이션
} catch (InterruptedException e) {
Log.e("ThreadDemo", "스레드 인터럽트 발생", e);
}
uiElement.setText("UI 변경 시도");
}
}).start();
}
}
이 코드는 앱이 강제 종료되며, 로그에는 다음과 같은 오류가 기록됩니다:
이 오류는 메인 스레드가 아닌 다른 스레드에서 UI 컴포넌트를 수정하려 할 때 발생합니다. UI 업데이트는 반드시 메인 스레드에서 수행해야 합니다. 따라서 백그라운드 스레드에서 작업을 완료한 후 메인 스레드로 돌아와 UI를 업데이트하는 방법을 알아야 합니다. 두 가지 대표적인 방법을 통해 위 문제를 해결해 보겠습니다.
방법 1: runOnUiThread() 메소드 활용
// UI 업데이트 방법 1:
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000); // 네트워크 작업 시뮬레이션
} catch (InterruptedException e) {
Log.e("ThreadDemo", "스레드 인터럽트 발생", e);
}
// 메인 스레드로 돌아가 UI 업데이트
runOnUiThread(new Runnable() {
@Override
public void run() {
uiElement.setText("방법1로 UI 업데이트");
}
});
}
}).start();
이 방법을 사용하면 UI가 성공적으로 업데이트됩니다.
방법 2: Handler 클래스 활용
Handler 객체를 생성하여 백그라운드 스레드에서 메시지를 전달하고 UI 업데이트를 수행할 수 있습니다.
// Handler 객체 생성
private Handler messageHandler = new Handler();
// UI 업데이트 방법 2:
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000); // 네트워크 작업 시뮬레이션
} catch (InterruptedException e) {
Log.e("ThreadDemo", "스레드 인터럽트 발생", e);
}
messageHandler.post(new Runnable() {
@Override
public void run() {
uiElement.setText("방법2로 UI 업데이트");
}
});
}
}).start();
두 방법 모두 효과적이지만, Handler는 더 복잡한 스레드 간 통신 상황에서 강력한 기능을 제공합니다. Handler의 다양한 활용 방법은 향후 글에서 더 자세히 다룰 예정입니다.