1. AsyncTask

핸들러를 사용하면 스레드를 사용하면서 UI 객체에 접근이 가능하지만, 

스레드 안에서 실행되는 코드와 핸들러 안에서 실행되는 코드가 구분되어야 하기 때문에 복잡하다.

AsyncTask를 이용하면 하나의 클래스 안에 스레드로 동작하는 부분과 UI 객체에 접근하는 부분을 함께 넣어 둘 수 있다.

즉, 하나의 작업 단위가 하나의 클래스로 만들어 질 수 있다.


onPreExecute()

doInBackground() 메서드가 호출되기 전에 onPreExcuted() 메서드가 호출된다.

스레드 작업 이전에 수행할 동작을 수행한다. 


doInBackground() 

스레드 안에서 실행될 코드를 작성한다.


onProgressUpdate()

UI에 접근할 코드를 작성한다.

doInBackground()에서 publicProgress() 메서드를 호출할 때마다 onProgressUpdate가 자동 호출된다.

전달 받은 데이터를 이용해서 중간중간 UI 업데이트를 한다.


onPostExecute()

UI에 접근할 코드를 작성한다.

모든 과정이 끝나고 나면, 즉 doInBackground() 메서드의 결과 값을 리턴받으면 onPostExecute() 메서드가 호출된다.




2. 구현 결과 화면

    



3. activity_main.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
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <ProgressBar
        android:id="@+id/progress_bar"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:progressBackgroundTint="@android:color/holo_blue_light"
        android:progressTint="@color/colorAccent"
        android:max="100"
        android:secondaryProgress="100"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
 
    <Button
        android:id="@+id/button"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:text="시작"
        android:textSize="20sp"
        app:layout_constraintTop_toBottomOf="@id/progress_bar"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
 
</android.support.constraint.ConstraintLayout>
 
cs



4. 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
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
package com.tistory.qlyh8.pracitice;
 
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
 
public class MainActivity extends AppCompatActivity  {
 
    ProgressBar progressBar;
    Button button;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        progressBar = findViewById(R.id.progress_bar);
 
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
             ProgressTask task = new ProgressTask();
             task.execute("시작");    // AsyncTask 실행
            }
        });
    }
 
    // 첫 번째 String 은 doInBackground(), 두 번째 Integer 는  onProgressUpdate(),
    // 세 번째 Integer 는 onPostExecute() 메서드의 타입을 지정한다.
    class ProgressTask extends AsyncTask<String, Integer, Integer>{
        int value = 0;
 
        // 가변길이 문자열 파라미터를 통해 몇 개의 문자열이건 전달해 줄 수 있다.
        @Override
        protected Integer doInBackground(String... strings) {
            while(true){
                if(value > 100)
                    break;
 
                value += 1;
                publishProgress(value);
 
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return value;
        }
 
        //  publishProgress()의 파라미터 타입과 onProgressUpdate()의 파라미터 타입이 같다.
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressBar.setProgress(values[0]);
        }
 
        // doInBackground() 결과 값의 타입과 onPostExecute()의 파라미터 타입이 같다.
        @Override
        protected void onPostExecute(Integer integer) {
            super.onPostExecute(integer);
            Toast.makeText(getApplicationContext(), "완료", Toast.LENGTH_LONG).show();
        }
    }
}
cs



5. 참고

- ProgressBar | Android Developers

https://developer.android.com/reference/android/widget/ProgressBar

- AsyncTask | Android Developers

https://developer.android.com/reference/android/os/AsyncTask

- 프로세스 및 스레드 | Android Developers

https://developer.android.com/guide/components/processes-and-threads




출처: https://www.edwith.org/boostcourse-android/lecture/17087/

핸들러를 이용한 스레드 구현 (1): http://qlyh8.tistory.com/83?category=726548


앞서 말한 방법으로는, 뷰에 접근할 때마다 새로운 핸들러를 정의하고 handleMessage() 에서 UI 접근 코드를 만들어야 하며

데이터를 메시지 객체로 만들어서 전달해야 하기 때문에 복잡하다.

이를 개선하기 위한 핸들러의 좀 더 쉬운 이용 방법이 있다.



1. 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
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
package com.tistory.qlyh8.pracitice;
 
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity  {
 
    TextView textView;
    Button button;
    Handler handler = new Handler();    // 핸들러 일반 객체를 사용한다.
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        textView = findViewById(R.id.text_view);
 
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Runnable 객체를 구현하여 스레드 생성
                new Thread(new Runnable() {
                    boolean isRunning = false;
                    int value = 0;
 
                    @Override
                    public void run() {
                        isRunning = true;
                        while(isRunning){
                            value += 1;
 
                            // post() 메소드를 호출하여 Runnable 객체를 전달한다.
                            // postAtTime(): 지정된 시간에 실행하는 메서드 
                            // postDelayed(): 지정된 시간만큼 딜레이 된 후 실행하는 메서드
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    // value 객체가 핸들러로 전달된다.
                                    // 핸들러 내부에서 실행되기 때문에, 이는 곧
                                    // 메인 스레드에서 실행되기 때문에 UI 접근이 가능하다.
                                    textView.setText("현재 값 : "+  value);
                                }
                            });
 
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start(); // 스레드 실행
            }
        });
    }
}
cs


2. 참고
- Communicating with the UI Thread
- 안드로이드 백그라운드 잘 다루기 Thread, Looper, Handler



출처: https://www.edwith.org/boostcourse-android/lecture/17086

'Android' 카테고리의 다른 글

소켓 (Socket) - 1. 소켓이란  (0) 2018.07.25
AsyncTask  (0) 2018.07.25
스레드 (Thread) - 2. 핸들러를 이용한 스레드 구현 (1)  (0) 2018.07.24
스레드 (Thread) - 1. 스레드와 핸들러  (0) 2018.07.24
Context (컨텍스트)  (0) 2018.07.20

1. 구현 결과 화면

    



2. activity_main.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
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="현재 값 : "
        android:textSize="25sp"
        android:textStyle="bold"
        android:textAlignment="center"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
 
    <Button
        android:id="@+id/button"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:text="스레드 시작"
        android:textSize="20sp"
        app:layout_constraintTop_toBottomOf="@id/text_view"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
 
</android.support.constraint.ConstraintLayout>
cs



3. 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
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
package com.tistory.qlyh8.pracitice;
 
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity  {
 
    TextView textView;
    Button button;
    ValueHandler handler = new ValueHandler();
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        textView = findViewById(R.id.text_view);
 
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                BackgroundThread thread = new BackgroundThread();
                thread.start(); // run() 메서드 호출
            }
        });
    }
 
    // 1초마다 값이 1씩 증가하는 스레드
    class BackgroundThread extends Thread {
        boolean isRunning = false;
        int value = 0;
 
        @Override
        public void run() {
            isRunning = true;
            while(isRunning){
                value += 1;
 
                Message msg = handler.obtainMessage(); // 메시지 객체를 참조
 
                Bundle bundle = new Bundle();
                bundle.putInt("value", value);
                msg.setData(bundle);
                handler.sendMessage(msg);   // 핸들러로 메시지를 보낸다.
 
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
 
    class ValueHandler extends Handler {
        @Override
        public void handleMessage(Message msg) { // 메시지 객체 처리
            super.handleMessage(msg);
            Bundle bundle = msg.getData();
            textView.setText("현재 값 : "+  bundle.getInt("value"));
        }
    }
}
cs

 





출처: https://www.edwith.org/boostcourse-android/lecture/17086

'Android' 카테고리의 다른 글

AsyncTask  (0) 2018.07.25
스레드 (Thread) - 3. 핸들러를 이용한 스레드 구현 (2)  (0) 2018.07.24
스레드 (Thread) - 1. 스레드와 핸들러  (0) 2018.07.24
Context (컨텍스트)  (0) 2018.07.20
ANR (Application Not Responding)  (0) 2018.07.17

+ Recent posts