티스토리 뷰
Thread?
- 프로세서 내에서 실행되는 세부 작업 단위
- 같은 프로세스의 다른 thread에서 코드와 데이터를 공유하게 됨
- multi-threading
메인 쓰레드 (=ui 쓰레드)
- 앱 실행시 기본적으로 생성되는 쓰레드
- 각종 생명주기 함수 처리 , 이벤트 처리 수행
- 보통 메인 스레드에서 5초 이상 블록되어 있으면 ANR(Application Not Responding) 발생으로 프로그램 중지여부를 결정해야 함
- 즉, 메인 쓰레드는 블록되어서는 안됨
작업 쓰레드
- 긴 처리 기산을 필요로 하는 작업 수행을 위해서 별도의 쓰레드 추가하여 사용하는것
- 안드로이드에서는 앱의 원활한 동작을 위해 메인 쓰레드에서 처리할 수 없는 일을 정의하고 있음, 예외 발생을 강제로 하여 정책을 지키도록 유도
- 메인쓰레드에서 처리할 수 없는 일 1) 디스크에서 파일쓰기 2) 디스크에서 파일 읽기 3) 네트워크 사용
--> 이러한 작업들은 작업 스레드를 이용해 처리하는것이 바람직함
- 작업 쓰레드의 구현 및 실행
= 쓰레드 객체 생성시 run() 메서드 재정의 java.lang.Thread 클래스, java.lang.Runnable 인터페이스 구현
= 쓰레드 객체에 대해 start() 메서드 호출로 Runnable 상태로 지정
= 이후 CPU를 할당 받으면 run() 메서드가 자동 호출되어 처리
* 작업 쓰레드의 종료
- 추가된 쓰레드의 run() 메서드가 끝나면 종료
- 추가된 쓰레드는 메인 쓰레드에서 종료 처리전까지는 무한 반복 수행하는 형태
- 그러나, 메인 쓰레드에서 다른 쓰레드의 종료를 강제할수는 없음
- 쓰레드의 종료처리과정필요
runOnUiThread란?
- 안드로이드는 싱글 쓰레드 체제, 오직 메인 쓰레드만이 뷰를 바꿀수 있기 때문에 이떄 핸들러를 통해서 전달함
Thread방법
1. extends Thread
2. implements Runnable
- Handler
- Looper
- AsyncTask
- HandlerThread
- ThreadpoolExecutor
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
package com.example.threadexample;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Handler mainHandler = new Handler();
private volatile boolean stopThread = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startThread(View view) {
stopThread = false;
// #1
// ExampleThread thread = new ExampleThread(10);
// thread.start();
// #2
// ExampleRunnable runnable = new ExampleRunnable(10);
// new Thread(runnable).start();
// #3
new Thread(new Runnable() {
@Override
public void run() {
//바로 Runnable 수행
// for(int i=0 ; i<10 ; i++){
// if(stopThread)
// return;
//
// Log.d(TAG, "startThread: " + i );
// try {
// Thread.sleep(1000);
//
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
}
}).start();
}
public void stopThread(View view) {
stopThread = true;
}
// #1
class ExampleThread extends Thread{
int seconds;
ExampleThread(int seconds){
this.seconds = seconds;
}
@Override
public void run() {
super.run();
for(int i=0 ; i<10 ; i++){
if(i==5){
/* mainHandler.post(new Runnable(){
@Override
public void run() {
Log.d(TAG, "run: ");
}
});*/
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "run: ");
}
});
}
Log.d(TAG, "startThread: " + i );
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// #2
class ExampleRunnable implements Runnable{
int seconds;
ExampleRunnable(int seconds){
this.seconds = seconds;
}
@Override
public void run() {
for(int i=0 ; i<10 ; i++){
if(stopThread)
return;
Log.d(TAG, "startThread: " + i );
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
|
cs |
thread와 handler을 직접 쓰는 건 좋은 방법이 아니기 때문에 JAVA에서는 다른 방법을 제공
* Thread, Runnable, Handler, Executor 차이점 정리
1. Service
- Activity랑 같지만 화면이 없는것!, 오래 걸리는 처리일때 사용
- 백그라운드 작업시 사용
- 직접적으로 사용하기 때 좀 피해야 함!
- 기본적으로 UI Thread이기 때문에 느려짐, 그래서 별도의 스레드 처리가 필요
- 다른 Component에 Bind 할 수 있음
- startServcie()로 시작하고, stopService()로 종료
- stopSelf()로 종료 가능
- 잘못사용가능할 확률이 높음 ...
2. IntentService
- Service를 상속 받아서 사용하도록 조금 더 편리하게 나온것
- API 30에서 deprecated되어 있기 때문에 JobIntentService로 바뀌어짐
- 기본적으로 백그라운드에서 Thread에서 동작, 그래서 따로 처리가 필요
- 작업이 순차적으로 수행되고, 한번에 하나의 작업만 수행됨
- onHandleintent()에서 작업 수행
3. JobIntentService
- Intentservice와 비슷하게 동작
- enqueueWork()로 실행
- onHandleWork()에서 동작처리
- 제한시간이 10분 -> 강제종료
- BIND_JOB_SERVICE 권한 필수
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application ..
<service android:name=".ExampleJobIntentService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>
MainActivity.java
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
|
package com.example.jobintentserviceexample;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private EditText edittextinput;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edittextinput = findViewById(R.id.edit_text_input);
}
public void enqueueWork(View view) {
String input = edittextinput.getText().toString();
Intent serviceIntent = new Intent(this, ExampleJobIntentService.class);
serviceIntent.putExtra("inputExtra", input);
ExampleJobIntentService.enqueueWork(this, serviceIntent);
}
}
|
cs |
ExampleJobIntentService.java
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
package com.example.jobintentserviceexample;
import android.bluetooth.BluetoothGattDescriptor;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
public class ExampleJobIntentService extends JobIntentService {
private static final String TAG = "ExampleJobIntentService";
static void enqueueWork(Context context, Intent work){
enqueueWork(context, ExampleJobIntentService.class, 123, work);
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: ");
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
Log.d(TAG, "onHandleWork ");
String input = intent.getStringExtra("inputExtra");
for (int i=0 ; i<10 ; i++){
if(isStopped()) return;
Log.d(TAG, "input + - "+ i );
SystemClock.sleep(1000);
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
@Override
public boolean onStopCurrentWork() {
Log.d(TAG, "onStopCurrentWork");
return super.onStopCurrentWork();
}
}
|
cs |
activity.xml
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
|
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/edit_text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Input"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="enqueueWork"
android:text="Enqueue Work"/>
</LinearLayout>
|
cs |
4. WorkManager
- 대부분의 서비스로 할 수 있는 것들을 대체 가능
- 오래 걸리는 작업을 Worker로 구현
- Worker를 기반으로 WorkRequest 작성
- WorkRequest는 한번 수행과 반복 수행이 있음
- 네트워크, 배터리 상태 등으로 트리거 가능
- WAKE_LOCK을 자체 관리하기 때문에 권한 추가로 ok
- foreground 서비스로 동작할 수 있음, 오랫동안 죽지 않는 서비스 작업이 가능해짐
<delay에 따른 선택>
- Service (기본 UI Thread)
- IntentService( 기본 백그라운드 Thread ) -> Job IntentService(1~10분)
- Work Manager
- 간단한 짧은 작업? -> Work Manager
- 긴 작업 -> Work Manager(foreground)
- 기존 intentService -> JobIntentService
- 긴 작업 + UI -> Serivce bind+foreground
-> 상황에 따라서 잘 사용하면 된다.
출처)
1. 사람만이 유투브
'Programming > Android' 카테고리의 다른 글
[Android/Jetpack] Navigation (safe args를 사용한) (0) | 2020.09.18 |
---|---|
[JAVA/Android] Android Architecture Components - MVVM, MVP, Clean 아키텍쳐 비교 (0) | 2020.09.18 |
[Android] android class 정리 (0) | 2020.08.31 |
[Android] 안드로이드 WebRTC 주의사항 (0) | 2020.08.25 |
[Android] 안드로이드 AppRTC 실행 및 오류 (0) | 2020.08.14 |