쓰레드는 동시작업을 할 수 있는 하나의 작업 단위이다.
즉, 동시에 여러작업을 하고 싶다면, 쓰레드들을 만들어 주어야 한다.
쓰레드를 배우기 전에 사용하는 안드로이드는 메인쓰레드 하나만 돌아가는 단일쓰레드 환경이다.
언제사용되나? 홈버튼을 누르거나 등의 행위를 할때 background 상에서 돌아가게 할수 있는데, 그떄 쓰레드가 사용된다.
핸들러란?
ㄴ 쓰레드를 여러 개만들더라도, UI를 담당하는 xml은 하나이상의 쓰레드들이 동시에 접근이 불가능하다.
따라서, 다른 쓰레드들에서는 핸들러 라는 제어 아래에서만 xml을 접근해야 한다.
ㄴ 즉, 핸들러는 각 쓰레드 안에서 생서하고, 여러개의 쓰레드가 동시에 접근하지 않고 요청한 순서대로 차례로 xml 에 접근하게 해주어서 "xml 동시접근" 에 대한 문제를 해결해준다.
=======================
예제
시계를 만든다고 고민해본다.
1 . 시간을 표시해줄 xml
2. 시간을 1초마다 새로고침해줄 코드 MainActivity 의 onCreate()에 작성
3. 실행해보면 매초 새로고침이 되기는 커녕 애초에 시간표시자체가 안된다.
3-1) 왜? onCreate가 끝나지 못하고 있다. onCreate는 메인쓰레드에서 실행되는 함수인데,
onCreate가 끝나지 않고있으니, 화면을 그리는 등의 다른 이벤트들을 시작도 못하고있는것이다.
3-2) 그러면? 메인메소드에서는 시간을 그려주는 행위만 하고, 매초 새로고침하는것은 특정 쓰레드에 뺴줄것이다.
@Override
protected void onCreate(Bundle savedInstanceState) {
clockTextView = findViewById(R.id.clock) ;
Calendar cal = Calendar.getInstance() ;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss") ;
//매초 새로고침되는 코드 작성
while (true) {
String strTime = sdf.format(cal.getTime());
clockTextView.setText(strTime) ;
try {
Thread.sleep(1000) ;
} catch (Exception e) {
e.printStackTrace() ;
}
}
}
4. 매초 시간을 업데이트하는 기능을 메인쓰레드에서 분리
4-1) onCreate() 액티비티가 실행될때 쓰레드를 만들어주어서 매초-새로고침이라는 기능을 적용
4-1-1) 쓰레드 만들기 : class new_ThreadName implements Runnable{ @Override public void run(){ . . . } }
4-2-2) void run() 함수 내부에 기능 적용
4-2) 설정이된 runable 클래스를 new Thread 매개변수로 주면서 start시킨다.
public class MainActivity extends AppCompatActivity {
TextView clockTextView ;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
clockTextView = findViewById(R.id.clock) ;
class NewRunnable implements Runnable {
Calendar cal = Calendar.getInstance() ;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss") ;
@Override
public void run() {
while (true) {
String strTime = sdf.format(cal.getTime());
clockTextView.setText(strTime) ;
try {
Thread.sleep(1000) ;
} catch (Exception e) {
e.printStackTrace() ;
}
}
}
}
NewRunnable nr = new NewRunnable() ;
Thread t = new Thread(nr) ;
t.start() ;
}
}
[번외] "Only the original thread that created a view hierarchy can touch its views."
원인 - "그리기 기능"은 반드시 메인 UI 스레드에서 실행되어야 합니다." 라는 조건에 어긋났음.
이유 - void run() 함수 내부에 setText 를 이용해서 xml을 조작했다.
즉, UI를 메인쓰레드가 아닌 특정 스레드에서 조작한것.
해결방법 - 특정 쓰레드에서 setText를 하지 않고 , "핸들러"의 "쓰레드간 메세지전송"기능을 이용해서 시간만 보내준다.
ㅇ 메인쓰레드에서 "쓰레드로 부터 온 메세지"를 받은 후, 가공해서 setText()를 해준다.
ㅇ 또는, 매시간마다 아무것도 없는 메세지를 보내주고, 메세지 받을떄마다 시간을 생성해서 setText해준다.
코드를 통해서 onCreate에서 어떻게 쓰레드와 핸들러를 생성하고, 생성된 쓰레드에서 핸들러로 메세지를 보내는지 확인해보겠다.
public class MainActivity extends AppCompatActivity {
TextView clockTextView ;
private static Handler mHandler ;
@Override
protected void onCreate(Bundle savedInstanceState) {
//s:핸들러생성
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Calendar cal = Calendar.getInstance() ;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String strTime = sdf.format(cal.getTime());
clockTextView = findViewById(R.id.clock) ;
clockTextView.setText(strTime) ;
}
} ;
//e:핸들러생성
//s:쓰레드생성
class NewRunnable implements Runnable {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace() ;
}
mHandler.sendEmptyMessage(0) ;
}
}
}
NewRunnable nr = new NewRunnable() ;
Thread t = new Thread(nr) ;
t.start() ;
}
//e:쓰레드생성
}
'안드로이드' 카테고리의 다른 글
해외 코딩인터뷰어들의 의견들을 통한 통찰 (0) | 2022.05.09 |
---|---|
프레그 먼트 종료 방법 (0) | 2020.04.30 |
Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class com.test.Com [Fragment Inflating Error] (0) | 2020.04.21 |
[10]안드로이드 액티비티 생명주기 (0) | 2020.04.21 |
[9]Fragment에 대한 기본적인 고찰 (0) | 2020.04.16 |