Android Studio) Thread / Handler

chaeyoung·2023년 1월 18일
0

Android Studio

목록 보기
8/13
post-thumbnail

ANR과 스레드-핸들러

액티비티 ANR

  • 액티비티 ANR(Application Not Responding): 액티비티가 사용자 이벤트에 반응하지 못하는 상황
    • ex. 사용자가 응답하지 않음(경고메세지) button 앱닫기 | 대기
    • 사용자 이벤트에 5초 이상 반응하지 못함: 액티비티 내 업무처리 로직 수행기간이 길기 때문
  • ANR 문제 발생 원인 네트워킹:
    • 서버 요청 ~ 응답까지 5초미만이라 판단, ANR문제 고려하지 않고 작성될 경우

ANR 문제 해결방법

  • `티비티의 수행 흐름을 추가:
    • 스레드(Thread)
      • '메인 스레드', '개발자 스레드'까지 두개의 스레드가 동작

      • 모든 스레드는독립적이고 병렬로 수행

      • 작성 방법

        1. 상속

          class MyThread extends Thread{
              public void run(){}
          }
          class ...{
          	MyThread thread = new MyThread();
            thread.start()
          }
        2. Runnable 인터페이스

          class MyThread implements Runnable{
          	public void run(){}
          }
          class ...{
            MyThread runnable = new MyThread();
            Thread thread = new Thread(runnable);
            thread.start()
          }
          • run()함수: 스레드 제어
            • sleep(){시간동안 대기상태}, wait(){순서따라 대기}, notify(){대기상태 깨우기} 사용 가능

핸들러(Handler)

스레드 - 핸들러 구조

  • 핸들러(Handler): 개발자 스레드에서 발생한 데이터로 뷰 업데이트

핸들러에 작업 의뢰

  • 개발자 스레드에게 뷰에 대한 작업 의뢰하는 방법: post(), sendMessage() 함수 이용

    Handler handler = new Hander()	// Handler 객체 생성
    
      // 뷰 관련 작업 담당 Runnable
      class UIUpdate implements Runnable{		// 개발자 스레드에 의해 호출되는 클래스
          public void run(){ textView.setText("sum:"+sum) } // 세번째 실행!!
      }
    
      // 개발자 스레드에서 뷰와 관련된 작업이 필요하다면 post()호출 후 UIThread에게 작업 의뢰
      class MyThread implements Runnable{
          int treadName;
          public void run(){		// 첫번째 실행!!
              for(int i=0; i<10; i++){
                  sum += i;
                  handler.post(new UIUpdate());	// 두번째 실행: 의뢰!!
                  try{
                      Thread.sleep(1000); 	// 10초대기
                  } catch (InterruptedException e){}
              }
        }
    }
    • 뷰에 접근하는 순간 handler.post() 이용해 UI스레드에게 의뢰 -> UI스레드는 Runnable 객체의 run() 함수를 자동 호출하는 구조

AsyncTask 와 Looper

AsyncTask

  • 스레드-핸들러구조 프로그램 방식
  • AsyncTask클래스: 스레드-핸들러의 추상화 개념
    • AsyncTask를 상속받는 클래스 작성
      • AsyncTask<type, type, type>:
        • 첫번째 타입: 백그라운드 작업을 위한 doInBackground()의 매개변수 타입과 동일
        • 두번째 타입: doInBack에 의해 발생한 데이터를 publishProgress()함수 이용해 전달, 이때 전달할 타입(onProgress와 동일하게 지정)
        • 세번째 타입: onPostExecute()함수의 매개변수 타입과 동일하게 지정
      class MyAsyncTask extends AsyncTask<Void, Intenger, String>{
      	protected String doInBackground(void... params){} // 꼭 재정의해서 사용
          
          protected void onProgressUpdate(Integer... values){}
          
          protected void onPostExecute(String values){}
      }
      • doInBackground(Params... params): 스레드에 의해 처리될 내용을 담는 함수(장시간 사용, run()에 해당하는 내용 작성)
      • onPreExecute(): AsyncTask작업 시작 전에 호출. AsyncTask에서 가장 먼저 한번 호출함
      • onPostExecute(Result result): 모든 작업이 완료된 후 가장 마지막에 한번 호출(doInBackground 최종 값 얻기 위해)
      • onProgressUpdate(Progress... value): doInBackground함수에 의해 중간 값 처리받아 호출

Looper

  • UI스레드와 개발자 스레드 간 핸들러에 대한 연동
    • Handler 역할: 전달받은 메세지를 메세지 큐에 담아줌
    • Looper 역할: 메세지 큐에 메세지가 담긴 순간을 감지하는 역할 + 담긴 메세지 추출 후 handlerMessage() 함수를 호출해주는 역할

Looper: 메세지 큐만 감지하는 일종의 감시자 역할

  • UI 스레드 + 개발자 스레드 간의 연동이 가능한 이유: 내부에 Looper가 존재하기 때문이다.

  • 예시: 개발자스레드 2개 간의 핸들러에 의한 연동

    class OneThread extends Thread{
    	Handler oneHandler;
      
      	public void run(){
          	Lopper.perpare();
          	public void handleMessage(Message msg){
              	int data = msg.arg1
                 if(msg.what == 0)
                  	Log.d("kkang","even data"+data);
                 else if(msg.what == 1)
                 	Log.d("kkang","odd data"+data);
              };
              Looper.loop();
          }
    }
    
    class TwoThread extends Thread{
    	public void run(){
      		Random random = new Random();
              for(int i=0; i<10; i++){
              	int data = random.nextInt(10);
                Message message = new Message();
                if(data%2==0) message.what = 0;
                else message.what=1;
                
                message.arg1 = data;
                oneThread.oneHandler.sendMessage(message);	// 다른스레드 사용
              }
      }
    }
    • Looper는 일종의 무한루프를 도는 작업으므로 종료설정이 꼭 필요
    // 생명주기 함수인 onDestory()에서 Looper 종료
    protected void onDestory(){
    	super.onDestory()l
      	oneThread.oneHandler.getLooper().quit();
    }

0개의 댓글