MainActivity

...더보기
 
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
package com.example.boostcoursepractice;
 
import android.os.AsyncTask;
import android.os.Bundle;
 
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
 
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
 
import androidx.annotation.NonNull;
import androidx.core.view.GravityCompat;
import androidx.appcompat.app.ActionBarDrawerToggle;
 
import android.view.MenuItem;
 
import com.google.android.material.navigation.NavigationView;
 
import androidx.drawerlayout.widget.DrawerLayout;
 
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
 
import android.view.Menu;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
 
public class MainActivity extends AppCompatActivity {
 
    TextView textView;
    ValueHandler valueHandler;
    Handler handler2;
 
    int value = 0;
    boolean running = true;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        valueHandler = new ValueHandler();
 
        handler2 = new Handler();
 
        textView = (TextView) findViewById(R.id.textView);
 
        Button button = (Button) findViewById(R.id.button);
 
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //new BackgroundThread().start();
 
                new Thread(new Runnable() {
 
                    int threadValue = 0;
                    //int value = 0;
 
                    @Override
                    public void run() {
                        running = true;
                        while (running) {
                            //value += 1;
                            threadValue += 1;
                            handler2.post(new Runnable() {
                                @Override
                                public void run() {
                                    value += 1;
                                    textView.setText("현재 값" + value);
                                }
                            });
 
                            try {
                                Thread.sleep(1);
                            } catch (Exception e) {
                            }
                        }
 
                        Log.d("JJH""threadValue 값 : " + threadValue);
                        //Log.d("JJH", "value 값 : " + value);
                    }
                }).start();
            }
        });
 
        Button button2 = (Button) findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //new BackgroundThread().start();
                new AsyncBackground().execute();
            }
        });
 
        Button button3 = (Button) findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                running = false;
            }
        });
 
        Button button4 = (Button) findViewById(R.id.button4);
        button4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //textView.setText("현재 값 : " + value);
            }
        });
    }
 
    class BackgroundThread extends Thread {
 
        int threadValue = 0;
        //int value = 0;
 
        public void run() {
            running = true;
            while (running) {
                //value += 1;
                threadValue += 1;
                Message message = valueHandler.obtainMessage();
                //Bundle bundle = new Bundle();
                //bundle.putInt("value", value);
                //message.setData(bundle);
                valueHandler.sendMessage(message);
                try {
                    Thread.sleep(1);
                } catch (Exception e) {
                }
            }
 
            Log.d("JJH""threadValue 값 : " + threadValue);
            //Log.d("JJH", "value 값 : " + value);
        }
 
 
    }
 
    class ValueHandler extends Handler {
 
        int sum = 0;
 
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
 
            value += 1;
            //Bundle bundle = msg.getData();
            //int value = bundle.getInt("value");
 
            textView.setText("현재 값 : " + value);
            //textView.setText("메세지큐의 마지막 값 : " + value);
        }
    }
 
    class AsyncBackground extends AsyncTask<String, Integer, Integer> {
        int threadValue = 0;
 
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            running = true;
        }
 
        @Override
        protected Integer doInBackground(String... strings) {
            while (running) {
                threadValue += 1;
                publishProgress();
                try {
                    Thread.sleep(1);
                } catch (Exception e) {
                }
 
 
            }
            return null;
        }
 
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
 
            value += 1;
            textView.setText("현재 값 : " + value);
        }
 
        @Override
        protected void onPostExecute(Integer integer) {
            super.onPostExecute(integer);
 
            Log.d("JJH""threadValue 값 : " + threadValue);
        }
    }
}
 
 
 
 
 
cs

 

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
35
36
37
38
39
40
41
<?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:orientation="vertical">
 
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="진행값"
        android:textSize="30dp" />
 
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="스레드 시작1" />
 
    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="스레드 시작2" />
 
    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="중지" />
 
    <Button
        android:id="@+id/button4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="진행값 확인" />
</LinearLayout>
 
cs

 

스레드는 우선 따로 클래스를 만들고 Thread를 상속 받아 그안에 run메서드를 오버라이드 하고 완성시킨 다음 그것을 .start() 시키면 실행된다. 우선 이런 스래드를 여러개 만들고 공유 자원을 동시에 사용하면 자바에서와 같이 동기화가 안된다. 여기서는 전역변수 value의 값을 올려주면서 확인 실험 해보았다.

또한 스레드 클래스 내부에서 UI접근이 아예 되지를 않는다. 이 UI접근불가문제를 해결하기 위해서 핸들러를 사용한다. 핸들러는 메인메서드에서 동작하고 받은 메세지를 큐처럼 쌓아놓고 해결하기 때문에 동기화가 된다.(여러 핸들러를 생성해 놓아도 하나의 큐에서 동작하는 것처럼 작동한다. 동기화 걱정 ㄴㄴ) 

핸드러를 쓰는 방법 첫번째(button2에 구현)로는 아래와 같이

 

class BackgroundThread extends Thread {

 

        int threadValue = 0;

        //int value = 0;

 

        public void run() {

            running = true;

            while (running) {

                //value += 1;

                threadValue += 1;

                Message message = valueHandler.obtainMessage();

                //Bundle bundle = new Bundle();

                //bundle.putInt("value", value);

                //message.setData(bundle);

                valueHandler.sendMessage(message);

                try {

                    Thread.sleep(1);

                } catch (Exception e) {

                }

            }

 

            Log.d("JJH","threadValue 값 : " + threadValue );

            //Log.d("JJH", "value 값 : " + value);

        }

 

 

    }

 

 

class ValueHandler extends Handler {

 

        int sum = 0;

 

        @Override

        public void handleMessage(@NonNull Message msg) {

            super.handleMessage(msg);

 

            value+=1 ;

            //Bundle bundle = msg.getData();

            //int value = bundle.getInt("value");

 

            textView.setText("현재 값 : " + value);

            //textView.setText("메세지큐의 마지막 값 : " + value);

        }

    }

 

주석 처리 되어있지만 메세지를 생성하여 그 안에 데이터가 들어있는 번들객체를 넣어 핸들러에 메세지를 전달해주면 받은 핸들러는 큐에 넣어 동작한다. 

 

두번째 방법(Button3 주석으로 구현)으로는 아래와 같이

 

new Thread(new Runnable() {

 

                    int threadValue = 0;

                    //int value = 0;

 

                    @Override

                    public void run() {

                        running = true;

                        while (running) {

                            //value += 1;

                            threadValue += 1;

                            handler2.post(new Runnable() {

                                @Override

                                public void run() {

                                    value+=1;

                                    textView.setText("현재 값" + value);

                                }

                            });

 

                            try {

                                Thread.sleep(1);

                            } catch (Exception e) {

                            }

                        }

 

                        Log.d("JJH","threadValue 값 : " + threadValue);

                        //Log.d("JJH", "value 값 : " + value);

                    }

                }).start();

 

바로 스래드를 생성하여 생성자안에 Runnuable클래스를 넣어주고 그안에 run을 오버라이드 해주고 또 거기서 생성된 오버라이드 하지 않은 일반 핸들러에 .post()라는 메서드를 호출하면서 매개변수로 Runnuable를 넣고 run메서드를 오버라이드 해주면 더 간단하게 구현할 수 있다.

 

어쨌든 이 모든 방식이 메인 메서드 안에 핸들러를 통해서 UI객체 접근이 이루어진다는 것을 잊지 말자.

 

 

 

 

 

마지막으로 AsyncTask를 알아보자

우선 클래스 구성은 아래와 같다.

 

 

class AsyncBackground extends AsyncTask<String, Integer, Integer> {

        int threadValue = 0;

 

        @Override

        protected void onPreExecute() {

            super.onPreExecute();

            running = true;

        }

 

        @Override

        protected Integer doInBackground(String... strings) {

            while (running) {

                threadValue += 1;

                publishProgress();

                try {

                    Thread.sleep(1);

                } catch (Exception e) {

                }

 

 

            }

            return null;

        }

 

        @Override

        protected void onProgressUpdate(Integer... values) {

            super.onProgressUpdate(values);

 

            value += 1;

            textView.setText("현재 값 : " + value);

        }

 

        @Override

        protected void onPostExecute(Integer integer) {

            super.onPostExecute(integer);

 

            Log.d("JJH""threadValue 값 : " + threadValue);

        }

    }

 

위 처럼 첫 실행시 onPreExecute()가 실행되며 doInBackground에는 일반전인 스레드 동작 코드를 넣어주면 되고 그 중간에  publishProgress()를 호출하면 그때마다 onProgressUpdate가 호출되어지는데 이 함수가 바로 핸들러의 역할을 하여 UI의 접근을 가능하게 해준다. 이때도 역시 큐처럼 동작하여 동기화에 신경쓰지 않아도 된다. 마지막에는 onPostExecute가 실행되며 스레드가 끝나게 된다. 

 

 

 

결과화면

 

+ Recent posts