일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 데이터베이스
- 코드리뷰
- 상대 레이아웃
- RecyclerView
- 레이아웃
- 테이블_레이아웃
- 리니어 레이아웃
- 액션바
- 안드로이드_프로그래밍
- 자바
- 텍스트뷰 스크롤
- Swift
- 뷰
- 프로그래밍
- 제약 레이아웃
- 드로어블
- 스낵바
- 수명주기
- edwith
- IOS
- SceneDelegate
- 안드로이드 스튜디오
- 안드로이드
- 코틀린
- 아이폰
- textview auto scroll
- 서비스
- 프로젝트
- 텍스트뷰 자동 스크롤
- 부스트코스
- Today
- Total
듀다의 성장개발로그
[부스트코스] 안드로이드 프로그래밍 18 - 스레드 본문
스레드는 무언가를 동시에 실행하기 위해서 생성하는 새로운 실행단위입니다.
앱의 기능을 구현하려면 어떤 기능을 동시에 실행시켜야 하는 경우가 있습니다.
예를 들면 슈팅게임을 만든다고 할 때, 화면에는 비행기가 여러 대인데 한 번에 한 대씩만 움직인다고 하면 재미가 없겠죠?
이 경우 스레드를 활용해서 동시에 움직이는 비행기를 구현할 수 있습니다.
이 포스팅에서는 안드로이드 스튜디오에서 스레드를 만들어 보고, 간단한 활용까지 해보도록 하겠습니다.
Thread 만들기
두 개의 버튼과 하나의 텍스트뷰를 가진 화면을 구성하여 '스레드 시작'을 클릭하면 스레드가 시작되고, '진행값 확인'을 클릭하면 스레드를 시작시킨지 몇 초가 지났는지 '진행값'부분에서 보여주는 앱을 만들어보겠습니다. 화면 구성은 그림과 같이 해 주시면 됩니다.
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
Button button = (Button)findViewById(R.id.button);
텍스트뷰와 첫번째 버튼을 다루기 위해, 뷰를 선언하고 정의해줍니다.
텍스트뷰는 다른 메소드에서도 다뤄질 것이므로, onCreate밖에서 선언하였습니다.
또, int형 변수 한 개도 있어야 합니다.
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(...).start();
}
});
버튼의 리스너를 설정해주는데, 첫번째 버튼에 넣을 기능은 '스레드 시작'이기 때문에 이 버튼을 클릭했을때 스레드가 생성되어야 합니다. onClick메소드 안에 스레드 객체를 생성합니다.
스레드는 객체로 구현됩니다. java.lang의 Thread클래스를 상속하여 새로운 스레드 클래스를 정의할 수도 있습니다.
여기서 다루는 것은 간단한 기능이기 때문에 Thread 클래스 객체를 그대로 사용하겠습니다.
위 코드에는 스레드의 인자가 명시되어 있지 않지만, 기능 실행을 위해 괄호(...) 안에 새 Runnable 객체를 넣어줍니다.
Runnable 인터페이스를 이용해 한 번 실행될 객체를 정의할 수 있습니다.
Runnable 객체의 run 메소드를 오버라이드하여 원하는 기능을 넣어주면 스레드가 실행되었을 때 Runnable이 생성되고 이 Runnable에서 run()을 호출하여 저희가 원하는 기능을 수행하게 됩니다.
- 참고 : Android 개발자 문서 Runnable
run안에는 저희가 만들고자 하는 기능인, 1초에 1씩 증가시키는 기능을 넣어야 합니다.
이 클래스에서 선언한 int형 변수를 1 증가시키고 이를 반복문에 넣어서 반복시킵니다.
try {
Thread.sleep(1000);
} catch (Exception e) {}
단, 숫자가 계속 늘어나기만 하면 지난 시간을 알 수 없겠죠? sleep(1000)으로 스레드를 1초동안 쉬게 합니다.
new Thread(new Runnable() {
boolean running = false;
@Override
public void run() {
running = true;
while(running) {
value += 1;
try {
Thread.sleep(1000);
} catch (Exception e) {}
}
}
}).start();
그러면 저희가 생성할 스레드에는 이러한 코드가 들어가게 되겠네요.
Button button2 = (Button)findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView.setText("현재 값"+value);
}
});
이제 두번째 버튼의 기능을 넣어줘야 합니다.
넣을 기능은 텍스트뷰의 내용을 바꾸는 게 전부이므로 간단히 구현할 수 있습니다.
버튼을 눌러 스레드를 시작하고 버튼을 눌러 진행 시간을 확인하는 앱이 완성되었습니다.
Handler 활용
그런데 매번 버튼을 눌러 진행값을 확인하는 것은 번거롭습니다.
실시간으로 확인하려면 어떻게 해야 할까요?
여기서 한 가지 주의해야 할 점이 있습니다.
앱을 실행하면 하나의 스레드가 시작되는데 이것을 메인 스레드라고 부를 수 있습니다.
이 메인 스레드에서는 UI에 접근할 수 있지만,
새로 생성한 스레드에서는 UI를 비롯하여 공동 메모리 리소스에 직접 접근할 수 없습니다. 여러 스레드가 한 곳에 동시에 접근하여 문제가 발생하는 것을 방지하기 위해 안드로이드에서 제한을 둔 것인데요,
여러 스레드가 리소스에 접근했을 때, 시스템에서 어느 것을 먼저 처리해야 하는지를 정하지 못하는 문제가 발생할 수 있기 때문입니다.
따라서 안드로이드에서는, 어떤 기능을 스레드에서 직접 접근하는 방식으로 구현하면 그 기능은 정상 동작하지 않도록 스레드의 메모리 직접 접근이 제한되어 있습니다.
직접 접근하지 않고 Handler라는 객체를 활용하면 접근이 가능합니다.
메인액티비티 클래스에서 Handler 객체를 만들고 첫번째 버튼의 onClick메소드 안에서 호출합니다.
그리고 Handler 객체에서 또다른 Runnable를 인자로 post메소드를 호출합니다.
새로 호출된 Runnable에 setText 메소드를 넣어 주면 실시간으로 현재 값이 변하게 됩니다.
int형 변수는 이제 스레드 안에서만 사용되니까 스레드 안에서 선언해도 되겠네요.
new Thread(new Runnable() {
int value = 0;
boolean running = false;
@Override
public void run() {
running = true;
while(running) {
value += 1;
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("현재 값 :" + value);
}
});
try {
Thread.sleep(1000);
} catch (Exception e) {}
}
}
}).start();
변경된 Thread 코드입니다.
AsyncTask
AsyncTask라는 객체를 이용해서 같은 기능을 구현할 수도 있습니다.
이 AsyncTask는 시작, 실행 중, 완료 시 실행할 동작들을 각각 지정해 줄 수 있는데요,
각각 doInBackground, onProgressUpdate, onPostExecute를 오버라이드하여 기능을 넣어줄 수 있습니다.
onProgressUpdate에서 UI업데이트를 수행하도록 앱을 만들면 위 프로그램과 같이 실시간으로 진행값이 변경되겠죠?
단, onProgressUpdate가 원하는 시점에 호출되어야 1초마다 진행값이 변하는 앱을 만들 수 있을 것입니다.
onProgressUpdate를 호출하는 시점은 doInBackground에서 publishProgress를 호출하는 시점이 됩니다.
같은 기능이 AsyncTask로 구현된 코드입니다.
class ProgressTask extends AsyncTask<String, Integer, Integer> {
int value = 0;
@Override
protected Integer doInBackground(String... params) {
while(true) {
if (value > 100) {
break;
}
value += 1;
publishProgress(value);
try {
Thread.sleep(1000);
} catch(Exception e) {}
}
return value;
}
@Override
protected void onProgressUpdate(Integer... values) {
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("현재 값"+value);
}
});
}
doInBackground는 AsyncTask를 실행하면 자동으로 호출되는 메소드입니다. 스레드 안에서 실행할 코드를 이 안에 넣어주면 됩니다. 인자인 String... params에서 "..."은 가변 길이 파라미터로, 몇 개의 문자열이건 전달받을 수 있다는 것을 의미합니다.
앱을 실행해보면 이전에 구현한 방식과 같이 1초마다 현재 값이 갱신됨을 확인할 수 있습니다.
'안드로이드 > 부스트코스' 카테고리의 다른 글
[부스트코스] 안드로이드 프로그래밍 - 프로젝트 D 코드 리뷰 (0) | 2020.03.06 |
---|---|
[부스트코스] 안드로이드 프로그래밍 19 - 서버와 서비스 (0) | 2020.03.06 |
[부스트코스] 안드로이드 프로그래밍 - 프로젝트 C 코드 리뷰 (0) | 2020.02.29 |
[부스트코스] 안드로이드 프로그래밍 17 - 액션바 만들기 (0) | 2020.02.28 |
[부스트코스] 안드로이드 프로그래밍 16 - 프래그먼트 만들기 (0) | 2020.02.28 |