일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 재택근무
- 한달어스
- 함수형 프로그래밍
- 베드테이블
- 리얼하다
- 지지않는다는말
- 면접
- 안드로이드
- 테트리스
- 좌식테이블
- 프래그먼트
- 브런치작가되기
- 북한살둘레길
- 소프시스
- 목적중심리더십
- 목적 중심 리더십
- 어떻게 나답게 살 것인가
- 슬기로운 온라인 게임
- 한달브런치북만들기
- T자형인재
- 한달독서
- 커스텀린트
- 소프시스 밤부 좌식 엑슬 테이블
- 캐치마인드
- 1일1커밋
- 자취필수템
- 베드트레이
- 끝말잇기
- 아비투스
- 한단어의힘
- Today
- Total
정상에서 IT를 외치다
[Android, Thread] Thread 넌 무엇이더냐? 본문
안녕하세요. 블랙진입니다.
안드로이드 개발을 하게되면 Thread(스레드)를 상황에 맞게 잘 사용해야 멋진 앱을 개발할 수 있습니다. 그럼 이 스레드란게 무엇일까요?
스레드란?
A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently. - 구글문서
프로그램 안에서의 실행을 담당하는 하나의 흐름입니다. Thread 는 한국어로 실을 뜻 합니다. 실처럼 한가닥의 실행 혹은 작업을 담당하는 역활을 하죠. JVM 은 어플리케이션이 동시에 수행할 수 있는 멀티 스레드를 할당할 수 있게 해줍니다. 이를 통해 어플리케이션은 동시에 여러 작업을 수행할 수 있게 됩니다.
JAVA 에서는 프로그램이 실행되면 최초의 스레드가 Main 스레드가 되어 실행됩니다. 이 메인스레드를 통해 여러 작업 스레드를 생성할 수 있습니다. 그러면 스레드를 어떻게 생성하는지 알아보겠습니다.
스레드를 생성하는 방법
1. Thread 클래스 사용
2. Runnable 인터페이스 사용
예제
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_centerInParent="true"
android:orientation="horizontal"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/mainText"
android:text="0"
android:textSize="30sp"
android:layout_marginRight="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/subText"
android:text="0"
android:textSize="30sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<Button
android:id="@+id/btnIncrease"
android:text="increase"
android:layout_below="@+id/linearLayout"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
두 개의 TextView 와 한 개의 Button 이 있습니다.
MainActivity.class
public class MainActivity extends AppCompatActivity {
private int mMainValue = 0;
private int mSubValue = 0;
private TextView mainText, subText;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise);
mainText = findViewById(R.id.mainText);
subText = findViewById(R.id.subText);
findViewById(R.id.btnIncrease).setOnClickListener(view -> {
mMainValue++;
mainText.setText(String.valueOf(mMainValue));
subText.setText(String.valueOf(mSubValue));
});
}
}
MainActivity 의 동작은 위와 같습니다. btnIncrease 를 누르면 mMainValue 값이 1씩 증가하게 되고 main 과 sub TextView에 값을 보여줍니다. 여기서 mMainValue 만 값이 증가되니 mSubValue 의 값을 작업 스레드를 만들어 증가시켜 보겠습니다.
1. Thread 클래스를 사용해 보자
MainActivity 내부에 subThread 클래스를 새로 만들어 줍니다. 이 클래스는 Thread 를 상속하고 있습니다.
class SubThread extends Thread {
@Override
public void run() {
while (true) {
mSubValue++;
try {
//1초의 간격을 줍니다.
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
MainActivity의 onCreate 안에 SubThread 를 생성 후 실행해 줍니다.
SubThread subThread = new SubThread();
//setDaemon를 설정하여 mainThread와 종료 동기화를 해줍니다.
//이렇게 안해줄 경우 어플이 종료 되어도 작업스레드는 계속 동작하게 됩니다.
subThread.setDaemon(true);
subThread.start();
2. Runnable 인터페이스를 사용해 보자
1번에서 상속하는 클래스만 Runnable 인터페이스로 변경해 줍니다.
class SubRunnable implements Runnable {
@Override
public void run() {
while (true) {
mSubValue++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
MainActivity의 onCreate 안에 Thread 를 생성 후 실행해 줍니다.
SubRunnable subRunnable = new SubRunnable();
Thread thread = new Thread(subRunnable);
thread.setDaemon(true);
thread.start();
1번의 방법이 동일하나 Thread 클래스를 생성한 후 생성자 파라미터로 Runnable 을 넣어 줍니다.
2-1. Runnable 인터페이스를 익명 클래스로 사용해 보자
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
mSubValue++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.setDaemon(true);
thread.start();
SubRunnable 클래스를 따로 생성하지 않고 new Runnable() 를 통해 익명 클래스로 만들어 보았습니다. 역시 동작은 모두 동일합니다.
이렇게 스레드를 생성하는 2가지 방법을 모두 살펴보았습니다.
3. 작업 스레드에서는 UI 작업을 할 수 없다
위 에제에서 버튼을 누르면 TextView에 변수 값이 문제없이 들어갑니다. 이는 메인스레드(UI 스레드)에서 View 에 접근했기 때문입니다. (View는 무조건 메인스레드를 통해서만 변경이 가능합니다) Activity 가 실행되면 그 안에서 작업 스레드를 새로 생성하지 않은 이상 처리하는 모든 과정은 메인스레드에서 일어난다고 생각하시면 됩니다. 만약 우리가 만든 SubThread 에서 View 에 접근하게 되면 어떻게 될까요?
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
mSubValue++;
//작업 스레드에서 view 에 접근하면 무슨일이 일어날까?
subText.setText(String.valueOf(mSubValue));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.setDaemon(true);
thread.start();
아래 에러와 함께 앱이 폭파됩니다...(펑)
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
에러를 보시면 생성된 original thread 에서만 view 를 건드릴 수 있다는 내용입니다. 이렇듯 View의 접근은 오직 메인스레드에서만 할 수 있게 되어 있습니다. 하지만 개발을 하다보면 작업 스레드에서 메인 스레드로 접근해야 되는 일이 발생할 수 있습니다. 그럼 이럴때 어떻게 해야될까요?
정답은 Handler 를 사용하는 것입니다
이와 관련되어 Handler 넌 무엇이더냐? 에서 이어서 포스팅을 진행하겠습니다.
<참고자료>
'안드로이드' 카테고리의 다른 글
[Android, Glide] Glide BitmapTransform 파헤쳐 보자! (2) | 2019.03.26 |
---|---|
[Android, Handler] Handler 넌 무엇이더냐? (0) | 2019.03.26 |
[Android, ExoPlayer2] ExoPlayer2 개념 및 사용방법 (3) | 2019.03.25 |
[Android, MediaPlayer] MediaPlayer 를 이용한 동영상 재생 (0) | 2019.03.25 |
[Android, OOM] 메모리릭과 OOM이란? (2) | 2019.03.23 |