티스토리 뷰

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.class123, 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. 사람만이 유투브 

 

 

 

 

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2025/02   »
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
글 보관함