Skip to main content

[번역] A journey on the Android Main Thread - Part 1

본 문서는 square engineering blog 에 기재된 A journey on the Android Main Thread - Part 1 기사를 번역한 것 입니다.

coding horrer 에 왜 우리는 소스 읽는 법 을 배워야 하는가 에 대한 기사 가 있습니다.
안드로이드의 가장 큰 특징 중 하나는 오픈소스 생태계 라는 점 입니다.

PSVM (public static void main)

public class BigBang {
 
public static void main(String... args) {
   
// The Java universe starts here.
 
}
}

모든 자바 프로그램은 public static void main() 메소드를 호출하면서 시작합니다.
이는 자바 데스크탑 프로그램, JEE 서블릿 컨테이너, 안드로이드 애플리케이션 이 모두 동일 합니다.

안드로이드 시스템은 부팅 단계에서 ZygoyteInit 이라 불리는 리눅스 프로세스를 실행합니다. 이 프로세스는 달빅VM 으로, 쓰레드에 안드로이드 SDK 의 대부분의 클래스 를 로드 하고 대기합니다.

새로운 안드로이드 애플리케이션을 시작할 때, 안드로이드 시스템은 ZygoteInit 프로세스를 포크 하게 됩니다. 포크된 자식 프로세스의 쓰레드는 대기를 해제하고, ActivityThread.main() 메소드를 호출합니다.



위키피디아 에 정의된 zygote 란 수정란을 의미합니다.

Loopers

계속 진행하기 앞서, 우리는 Looper (이하 루퍼) 클래스를 살펴 볼 필요가 있습니다.
루퍼를 사용하는 것은 하나의 쓰레드가 메시지들을 연속해서 실행하도록 하는 좋은 방법 입니다.

각각의 루퍼는 메시지 객체의 큐를 지니고 있습니다. (이를 메시지 큐 MessageQueue 라고 합니다.)

루퍼는 큐에있는 각각의 메시지를 실행하고, 큐가 비었을 때에는 정지(차단)하는 loop() 메소드를 지니고 있습니다.

Looper.loop() 메소드는 아래와 유사합니다.

void loop() {
 
while(true) {
   Message message
= queue.next(); // blocks if empty.
   dispatchMessage
(message);
   message
.recycle();
 
}
}

각각의 루퍼는 하나의 쓰레드에 연결되어 있습니다. 새로운 루퍼를 생성하고 현제 쓰레드에 연결하기 위해서는 여러분은 반드시 Looper.prepare() 메소드를 호출해야 합니다.

루퍼들은 Looper 클래스안에 스테틱으로 정의된 ThreadLocal 에 저장 됩니다.
여러분은 Looper.myLooper() 메소드를 호출함으로 써 현제 쓰레드에 연결된 루퍼 를 검색할 수 있습니다.

HandlerThread 클래스는 여러분들을 위해 이 모든것을 대신해 줍니다.

HandlerThread thread = new HandlerThread("SquareHandlerThread");
thread
.start(); // starts the thread.
Looper looper
= thread.getLooper();

코드는 다음과 같습니다.

class HandlerThread extends Thread {
 Looper looper
;
 
public void run() {
   Looper
.prepare(); // 루퍼를 생성하고 ThreadLocal 에 저장 합니다.
   looper
= Looper.myLooper(); // Retrieve the looper instance from the ThreadLocal, for later use.
   Looper
.loop(); // Loop forever.
 
}
}

Handlers

핸들러는 루퍼와 매우 잘 어울립니다.

핸들러는 두가지 목적을 지니고 있습니다:

  • 다른 쓰레드로 부터 루퍼의 메세지 큐에 메세지를 전달 합니다.
  • 그 루퍼와 연결된 쓰레드에서 루퍼의 대기열의 메시지를 처리합니다.

// 각각의 핸들러는 하나의 루퍼와 연결되어 있습니다.
Handler handler
= new Handler(looper) {
 
public void handleMessage(Message message) {
   
// Handle the message on the thread associated to the given looper.
   
if (message.what == DO_SOMETHING) {
     
// do something
   
}
 
}
};
// Create a new message associated to that handler.
Message message
= handler.obtainMessage(DO_SOMETHING);
// Add the message to the looper queue.
// Can be called from any thread.
handler
.sendMessage(message);

여러분은 하나의 루퍼에 여러 핸들러를 연결할 수 있습니다. 루퍼는 message.target 에 메시지를 전달 합니다.

핸들러를 사용하는 인기있고 간편한 방법은 Runnable 을 전달하는 것 입니다.

// Create a message containing a reference to the runnable and add it to the looper queue
handler
.post(new Runnable() {
 
public void run() {
   
// Runs on the thread associated to the looper associated to that handler.
 
}
});

또한 핸들러는 루퍼를 제공하지 않고도 생성이 가능합니다.

// DON'T DO THIS
Handler handler
= new Handler();

인자가 없는 핸들러 생성자는 Looper.myLooper() 를 호출하게 되고, 현재 쓰레드와 연결된 루퍼를 검색하게 됩니다.
이는 여러분인 핸들러로 연결하고 싶은 쓰레드일 수도 있고 아닐수도 있습니다.

대개, 여러분은 단지 메인 쓰레드에 전달하는 핸들러를 생성하고 싶으실 것 입니다.

Handler handler = new Handler(Looper.getMainLooper());

Back to PSVM

다시 ActivityThread.main() 을 살펴봅시다. 기본적으로 수행하는 것은 아래와 같습니다.

public class ActivityThread {
 
public static void main(String... args) {
   Looper
.prepare();

   
//이제 여러분은 Looper.getMainLooper() 를 호출함으로써 언제든지 메인 루퍼를 검색 할 수 있습니다.
   Looper
.setMainLooper(Looper.myLooper());

   
// 루퍼에 첫번째 메시지를 전달합니다.
   
// { ... }

   Looper
.loop();
 
}
}

이제 여러분은 쓰레드가 메인 쓰레드에서 호출되는 이유에 대해 이해하셨을 것 입니다.

Note : 예상하신 바와 같이, 메인 쓰레드가 첫번째로 할 동작 중 하나는 Application 을 생성하고 Application.onCreate() 를 호출 하는 것 입니다.

다음 시간에는 안드로이드 생명주기와 메인 쓰레드 간의 관계에 대해 살펴 보면서, 어떻게 복잡한 버그를 만들어 내는지도 살펴 볼 것 입니다.

Comments

Popular posts from this blog

Google Press Event 7/24/13

Sundar Pichai 와 함께한 아침. Google 은 3가지 새로운 제품에 대한 발표를 하였습니다. 1. 2nd Nexus7 첫번째는 이미 소문이 무성했던 Nexus7 입니다. 성능이 대폭 향상되었습니다. Nexus 7 발매와 더불어 google app 들이 업데이트 되었고, Google Play Game 과의 연계성도 더욱 향상되었습니다. 4G LTE 는 미국에만 제한적으로 사용될 것으로 보입니다. 가격은 다음과 같습니다. - 16GB WIFI : $229 - 32GB WIFI : $269 - 32GB LTE : $349 조만간 발매될 국가에 한국도 포함되어 있습니다. (만세!) Google Play 에서 판매 예정이라고 합니다. 개인적으로 고화질 디스플레이 와 OpenGL|ES 3.0 이 지원되면서 게이밍 기능이 향상된 점을 강조하는 것이 눈에 띄였습니다. 아마도 멀티미디어 적인 기능향상으로 인한 자신감이 아닐까요. 2. Android 4.3 두번째로 Android 4.3 에 대한 소식입니다. 새로운 기능들이 많이 추가되었습니다. 4.3 APIs  는 바로 다운 받을 수 있습니다. http://developer.android.com/about/versions/jelly-bean.html 개인적으로 눈에 띄는 APIs 는 ActionBar 가 드디어 하위버전을 지원하기 시작했다는 것 입니다. new v7 appcompat library 에 추가 된 사항으로 Android 2.1(API level 7) 까지 지원합니다. 이를 지원하기위해  ActionBarActivity class 가 새로이 추가 되었습니다. 3. Chromecast 위 두 소식은 이미 들은 이야기가 많았지만 chromecast  는 좀 생소했습니다. 쉽게 생각해서 Apple 의 AirPlay 와 흡사하다고 보시면 될 것 같습니다. ...

[리뷰] 스위프트 프로그래밍

스위프트 3 가 발표된 이후로 국내에도 스위프트 3 내용을 다루는 책들이 하나둘씩 출간되고 있습니다. 그리고 지금부터 이야기할 <스위프트 프로그래밍> 역시 그중 한 권입니다. 이 책은 기존에 있던 책들과는 달리 iPhone이나 Mac App 개발에 필요한 내용을 다루지는 않습니다. 개인적으로는 이러한 점 때문에 스위프트란 언어 자체에 좀 더 집중할 수 있었습니다. 책은 크게 다섯 개의 파트로 구성되어 있으며 각 파트별 목차는 다음과 같습니다. Part Ⅰ 스위프트 기초 1. 스위프트 2. 스위프트 처음 시작하기 3. 데이터 타입 기본 4. 데이터 타입 고급 5. 연산자 6. 흐름 제어 7. 함수 8. 옵셔널 Part Ⅱ 객체지향 프로그래밍과 스위프트 9. 구조체와 클래스 10. 프로퍼티와 메서드 11. 인스턴스 생성 및 소멸 12. 접근제어 Part Ⅲ 함수형 프로그래밍과 스위프트 13. 클로저 14. 옵셔널 체이닝과 빠른종료 15. 맵, 필터, 리듀스 16. 모나드 Part Ⅳ 확장 17. 서브스크립트 18. 상속 19. 타입캐스팅 20. 프로토콜 21. 익스텐션 22. 제네릭 23. 프로토콜 지향 프로그래밍 Part Ⅴ 스위프트 고급 24. 타입 중첩 25. 패턴 26. where 절 27. ARC 28. 오류처리 Part1, 2  까지는 스위프트 언어에 대한 기본적이고 전반적인 내용을 설명합니다. 스위프트를 처음 배우는 독자뿐만 아니라 스위프트를 조금 공부해 본 독자에게도 유용한 내용이 많았습니다. 특히, 스위프트 언어를 사용하는 데 있어 지켰으면 하는 규칙을 반복적으로 설명함으로써 자연스럽게 그러한 규칙이 손에 익히도록 한 점이 좋았습니다. 다만 중간중간 난이도가 갑자기 높아지는 부분이 있어 초심자에게는 책 앞부분에서 조금 힘들 수도 있겠다는 생각이 들었습니다. Part3  는 아마도 이 책에서 가장 ...

[Googe I/O 2014] 국산 재료로 Cardboard 만들기!

올해 Google I/O 에서 가장 흥미있었던 내용중 하나가 바로 Cardboard 였다고 한다. 사실 난 Android L Preview 와 Material Design 에 때문에 상대적으로 이녀석을 홀대하고 있었는데, 회사 선임님께서 요놈이 얼마나 대단한 녀석인이 알려주신 덕분에 관심을 갖게 되었다. 더군다나 제작 방법은 물론 Libraray 까지 제공하다니... 그래서 바로 만들기로 결정. 우선 아래 사이트를 참고하자. 1. Reference SIte - Cardboard 제작 - Cardboard API 사이트를 들어가면 친절하게 구매할 수 있는 사이트까지 링크되어 있으나...전부 아마존. 참고로 이 글을 쓰고 있는 지금까지 아마존에서 주문한 렌즈를 받지 못했다.(한 2주 된듯.) 그래서! 결국 국내에서 파는 제품들로 꾸려보기로 했다. 순수 국내산으로~ 이미 nurinamu 님 께서 블로깅을 하셨지만... 여튼. 필수 재료는 아래를 참고하자. 2. 국내에서 구입한 재료 목록 1)  렌즈 - 양면 볼록 렌즈 : 유리 / 직경 : 30mm / 초점거리 : 46mm (한알당 3,300원) 2)  자석 - 네오디움 원형사라 자석 : 지름 : 20mm / 두께 4T (1,460원) - 페라이트 자석 : 지름 : 20mm / 두께 5.0mm (2,000원) 3)  골판지 - 택배 박스 사용 (0원) NFC 는 집에서 저장할 방법도 없으니 Pass. 고무줄이나 밴드는 취향에 맞게... 사실 도면도 공개되어 있고, 재료만 구하면 만드는건 쉽다. 굳이 설명을 하자면... 자르고... 자르면 ... 골격완성! 그리고... 오랜 기다림 끝에 결국 받지못한 아마존 렌즈를 뒤로하고, 국내 사이트에서 주문한 렌즈를 끼워주면... (국내산 렌즈는 오전에 주문하고 다음날 점심에 바로 겟.) 이렇게 완성! 개인적으로 신기했던 것중 하나...