본문 바로가기

개발 코딩 정보 공유/안드로이드 자바 코틀린

UI쓰레드에서 긴작업을 하면 안되는 이유

 

 

안드로이드 지식 공유

 

 

 

 

 

 

 

UI 쓰레드와 백그라운드 쓰레드

 

 

  Main 쓰레드와 백그라운드 쓰레드를 어떻게 사용해야 할까? 저는 안드로이드 개발 초기에 UI 개발에 대한 개념이 부족하다 보니 많은 어려움이 있었습니다. 게다가 쓰레드에 대한 개념이 명확하지 않아서 정확하게 일을 처리할 수 없었죠. 지금은 쓰레드가 너무 재미있습니다. 기억을 거슬러 한번 정리하면서 메인쓰레드, 백그라운드 쓰레드를 언제 만들어서 사용하는지 구분해서 알아보겠습니다. 몇가지 규칙을 지킨면 그야말로 유저친화적인 앱을 만들수 있습니다.

 

   1. 긴 시간이 걸리는 작업은 반드시 백그라운드 작업자를 통해 사용하도록 한다

   2. UI(화면) 관련 제어가 필요하다면 반드시 UI 쓰레드(Main Thread)에게 맡겨라

 

이것이 전부 입니다. 간단하죠? 이 규칙을 지키는 것만으로 유저가 원하는 반응형 앱을 만들수가 있는 것이죠. 그럼 한번 만들어 보시죠!

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
//버튼을 만들어 주고
//텍스트상자를 하나 만들어주겠습니다.
 
private Button btn1;
private Button btn2;
private TextView txt1;
 
 
...
 
 
btn1 = findViewById(R.id.longWork);
btn2 = findViewById(R.id.longWork2);
txt1 = findViewById(R.id.longWorkMsg);
cs

 

 

버튼과 텍스트뷰를 이용해 간단한 작업을 해보겠습니다. btn1은 UI쓰레드에서 긴작업을 진행할때, btn2는 백그라운드 쓰레드를 생성하여 진행할때 입니다. 그에 따른 상태를 텍스트뷰에 표시 해보도록 하겠습니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
btn1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //긴 시간의 작업을 아무생각없이 시작하면
        //ANR 메세지를 만나게 된다
 
        txt1.setText("1번 작업을 시작합니다.");
        longTimeWorks();
        txt1.setText("1번 작업을 완료 하였습니다.");
     }
});
 
...
 
/**
 * 긴 시간이 걸리는 작업을 실행한다
 */
private void longTimeWorks(){
    try{
        Thread.sleep(10000); //10초 가량의 작업을 가정...
    }catch(Exception e){
        //ignore
    }
}
cs

 

 

btn1 을 누르게 되면 longTimeWorks 라는 메서드를 실행하게 했습니다. 이 안에는 긴작업이라는 가정하에 10초의 시간을 두었습니다. 버튼을 누르는 순간! 눌렀던 버튼은 눌러진채 나오질 않습니다. 화면도 역시 멈춰버리죠. 얘네 왜 이러는 거죠??? 10초를 기다린 후에야 화면은 정상으로 돌아옵니다.

 

 

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
        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //긴 작업은 절대 메인쓰레드에서 동작시키면 안된다
                //백그라운드 쓰레드를 통해 작업한다
 
                txt1.setText("2번 작업을 시작합니다.");
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        longTimeWorks();
                        //백쓰레드에서는 UI에 손대면 안된다
                        //UI 관련 작업은 반드시 메인쓰레드에게 시키도록 한다
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                txt1.setText("2번 작업을 완료 하였습니다.");
                            }
                        });
 
                    }
                });
                t.setName("MyBackground-Thread");
                t.start();
 
            }
        });
cs

 

 

btn2 의 경우 백그라운드 쓰레드를 하나 생성해서 긴 시작의 작업을 실행해 보겠습니다. 이제는 화면이 멈추거나 하는 일이 발생하지 않네요. 아! 동작을 마치고 runOnUiThread를 통해 상태 메세지를 전달하는것 잊지 마시구요^^ (반드시 UI 를 제어 하는 작업은 메인쓰레드에게 맡기셔야 합니다) 사실 이 예제는 문제가 있습니다. 버튼을 여러번 누르게 되면 누르는 횟수만큼 쓰레드를 생성하니 말이죠. 이는 효율성과 거리가 머네요. 전편에서 알아봤던 HandlerThread 를 사용한다면 어떨까요? 단일 루퍼와, 큐를 통해 일이 순차적으로 실행될테니 쓰레드를 계속 생성할일은 없겠네요. 적당히 개발 상황에 맞게 응용하는게 중요하겠습니다.