일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 안드로이드 os 구조
- 안드로이드 유닛테스트란
- 서비스 쓰레드 차이
- 2022 플러터 설치
- jvm이란
- android ar 개발
- 안드로이드 유닛 테스트 예시
- 안드로이드 라이선스
- 큐 자바 코드
- 클래스
- 안드로이드 유닛 테스트
- ar vr 차이
- 자바 다형성
- rxjava hot observable
- rxjava cold observable
- 스택 자바 코드
- 멤버변수
- 안드로이드 레트로핏 사용법
- Rxjava Observable
- 2022 플러터 안드로이드 스튜디오
- 객체
- android retrofit login
- rxjava disposable
- ANR이란
- 안드로이드 라이선스 종류
- 서비스 vs 쓰레드
- 플러터 설치 2022
- jvm 작동 원리
- 안드로이드 레트로핏 crud
- 스택 큐 차이
- Today
- Total
나만을 위한 블로그
[Android] 핸들러란? 루퍼란? 본문
참고한 사이트 :
https://itmining.tistory.com/5
http://blog.naver.com/PostView.nhn?blogId=huewu&logNo=110115454542
https://blog.naver.com/crowdark7/109380704
https://recipes4dev.tistory.com/170
핸들러 : handle + er, 뭔가를 다루는 사람이란 뜻이다.
안드로이드의 핸들러 : 다른 객체들이 보낸 메시지를 받고 이를 처리하는 객체. 개발자들은 자체적인 메시지를 정의할 수 있다. 그리고 메시지를 처리하는 핸들러를 구현해 메시지 처리 방식의 프로그램이 구현된다.
메시지 큐에 보낼 데이터를 넣고 루퍼를 통해 처리할 데이터를 받고 보내는 중간 관리자 역할을 하는 것.
하나의 핸들러는 하나의 쓰레드와 바인딩된다.
핸들러가 필요한 이유
안드로이드 안에서 병렬 처리로 돌아가는 메인과 서브 쓰레드에서 같은 textview를 setText()했을 때 어떤 쓰레드의 명령을 따라야 하나?
이런 동기화 문제를 해결하기 위해 안드로이드는 메인 쓰레드에서만 UI 작업이 가능케 했다. 다른 쓰레드에서 UI 쓰레드에 간섭하려면 핸들러, 루퍼를 써서 서브 쓰레드에서 메인 쓰레드로 UI 처리 작업을 전달하든지, UI 쓰레드에서 자체 해결해야 한다.
핸들러는 Message, Runnable 객체를 처리한다. Runnable 메시지(Thread(Runnable r) 생성자를 만들어서 Runnable 인터페이스를 구현한 개체를 생성해 상속받은 쓰레드는 추상 메서드 run()을 반드시 구현해야 하는 것)는 run()을 호출해 처리하고 Message는 handleMessage()를 이용해 처리한다. 흐름은 아래와 같다.
1. 메시지는 다른 쓰레드에 속한 메시지 큐에서 전달된다.
2. 메시지 큐에 메시지를 넣을 땐 핸들러의 sendMessage()를 이용한다.
3. 루퍼는 메시지 큐에서 Loop()을 통해 반복적으로 처리할 메시지를 핸들러에 보낸다.
4. 핸들러는 handleMessage()를 통해 메시지를 처리한다.
중요한 것은 핸들러는 의존적이라는 것이다. 메시지 큐가 있어야 하고, 메시지를 전달할 루퍼가 없으면 핸들러의 handleMessage()는 쓰이지 못한다. 즉, 핸들러는 쓰레드, 루퍼, 메시지 큐가 꼭 필요하다.
핸들러를 얻는 방법은 new 키워드를 써서 Handler 클래스의 객체를 만들기만 하면 된다.
그러면 새 Handler 인스턴스는 자동으로 해당 쓰레드와 메시지 큐에 연결(바인딩)되고, 이 시점부터 핸들러를 통해 메시지를 보내고 처리할 수 있게 된다.
이 핸들러라는 건 쓰레드 당 반드시 하나만 생성할 필요는 없다. 오히려 하나의 핸들러에서 모든 메시지를 처리하는 것보다 메시지의 종류, 기능에 따라 여러 핸들러로 나눠 처리하는 게 더 좋다. 물론 메시지를 보내는 쓰레드에서 적절한 핸들러를 선택해 메시지를 보내는 건 잊지 말아야 한다.
- 루퍼(Looper) : 루퍼의 Loop은 반복한다는 뜻이다. 즉, 루퍼는 뭔가를 반복해서 수행하는 놈이라는 뜻으로 생각된다. 자바의 반복문같이 뭔가를 반복한다는 건데 어떤 것을 반복하는걸까?
디벨로퍼의 루퍼 : 쓰레드에 대한 메시지 루프를 실행하는 데 사용되는 클래스. 쓰레드에는 기본적으로 메시지 루프가 없다. 하나를 만들려면 루프를 실행할 쓰레드에서 Preparing()을 호출한 다음 loop()를 호출해 루프가 중지될 때까지 메시지를 처리하도록 한다.
메시지 루프와의 상호작용은 대부분 핸들러 클래스를 통해 이뤄진다. 이것은 루퍼 쓰레드 구현의 전형적인 예시다. prepare()와 loop()을 분리해 루퍼와 통신할 초기 핸들러를 만들어라.
루퍼란 쓰레드를 통해 생성되고 계속 반복적으로 어떤 일을 처리하는 것이다. 이 일은 바로 메시지 큐에 들어있는 메시지들을 읽는 일이다.
이는 메시지 큐가 비어있는 동안엔 아무 일도 안 하다가, 메시지 큐에 메시지가 들어오면 이걸 꺼내서 적절한 핸들러로 전달하는 일을 계속 반복해서 수행한다.
하나의 쓰레드를 점유해서 메시지 큐만을 위해 일하는 놈을 루퍼라고 할 수 있겠다.
안드로이드 프로세스엔 1개의 메인 쓰레드가 있고 메인 쓰레드는 내부적으로 루퍼를 통해 메시지 큐에 핸들러를 통해 데이터를 읽고 그걸 다시 핸들러를 통해 보내준다.
위에서 쓰레드는 기본적으로 루퍼가 없다고 했는데, 여기서 말한 쓰레드는 개발자가 만든 쓰레드를 말하는 것이고 안드로이드의 메인 쓰레드(UI 쓰레드)에는 기본적으로 루퍼가 내재되어 있다.
즉, 안드로이드의 메인 쓰레드에는 루퍼 객체를 써서 메시지 루프를 실행하는 코드가 이미 구현돼 있고, 해당 루프 안에서 메시지 큐의 메시지를 꺼내 처리하도록 만들어져 있다. 개발자가 할 일은 메인 쓰레드로 전달할 메시지 객체를 구성하고, 쓰레드의 메시지 큐에 연결된 핸들러를 통해 해당 메시지를 보내는 것이다.
또한 안드로이드는 루퍼를 포함하는 쓰레드를 만드는 방법을 2개 제시하고 있다.
하나는 임의의 쓰레드에서 직접 루퍼를 만드는 방식이다.
특정 쓰레드 안에서 Looper.prepare()를 통해 메시지 큐를 준비하고 원하는 핸들러를 만든다.
그리고 run()의 마지막에 Looper.loop()를 호출하면 메시지 큐에 메시지가 전달되는 걸 기다리던 루퍼가 일하기 시작한다.
주의할 것은 loop()는 기본적으로 무한 루프를 도는 함수라서, 생성된 쓰레드는 외부 쓰레드에서 루퍼의 quit()을 호출하지 않는 이상 종료되지 않는다는 것이다.
두번째는 HandlerThread 클래스를 활용하는 방법이다.
HandlerThread t = new HandlerThread("My Handler Thread");
t.start();
handler = new Handler(t.getLooper());
HandlerThread는 기본적으로 루퍼를 갖고 있으며 getLooper()로 포함된 루퍼를 얻어오거나, quit()으로 루퍼의 무한 루프를 정지시킬 수 있다. 단 여기서의 quit()는 메시지 큐에서 새 메시지를 꺼내 오는 루프를 중단할 뿐이지 연결된 핸들러 단에서 진행중인 작업이 중간에 종료되는 건 아니다.
명시적인 루퍼가 필요하다면 이걸 쓰는 편이 낫다.
'Android' 카테고리의 다른 글
[Android] Cannot open a library at FileMapping 에러 (0) | 2019.11.26 |
---|---|
[Android] 태그란? (0) | 2019.11.25 |
[Android] 콜백이란? 리스너란? (0) | 2019.11.24 |
[Android] 뷰페이저, 카드뷰 사용 위한 implementation 코드 (0) | 2019.11.24 |
[Android] SQLite란? - 1 - (0) | 2019.11.23 |