티스토리 뷰

728x90
반응형

Message.obtain() vs Handler.obtainMessage()

Handler 에 대해 찾다가 Message 객체를 얻어오는 두 메소드를 알게 되었다.

두 메소드의 차이를 보려고 Android Developers 문서를 보았는데 둘 다 Global Message Pool 의 인스턴스를 반환한다고 명시되어 있었다.

무언가 다른 점이 있을것 같아 찾아본 내용들에 대해서 정리하고자 한다.

Message.obtain()

Android Developers 에서 찾아보면 이렇게 정의되어있다.

obtain

static fun obtain(): Message!

Return a new Message instance from the global pool. Allows us to avoid allocating new objects in many cases.

Global Message Pool 에서 새 Message 인스턴스를 반환한다. 많은 경우 새로운 객체의 할당을 피할 수 있다.

Global Message Pool

나는 정의를 보면서 global message pool 이 무엇인지가 궁금했는데, Message.java 코드를 살펴보면 알 수 있다.

private static Message sPool;   // Message pool
private static final int MAX_POOL_SIZE = 50; // Message pool max size

public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}

코드를 보면 단순히 Message class 내의 재활용되는 정적 메시지 객체이다.

그런데 13번 라인을 보면 sPool == null 일 때, 새 Message 객체를 생성하여 리턴하는데 일반적으로 알고있는 싱글턴과 다르게 설계되어있다. 이는 Message.recycle() 을 보면 알 수 있다.

/**
* Return a Message instance to the global pool. You MUST NOT touch
* the Message after calling this function -- it has effectively been
* freed.
*/
public void recycle() {
clearForRecycle();

synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}

위 메소드를 통해 메시지 인스턴스를 global message pool 에 되돌린다.

recycle()Handler.dispatchMessage(Message msg) 가 한 번 호출되고 난 뒤에 호출된다고 한다.

Handler.dispatchMessage(Message msg)

Looper.loop() 에서 MessageQueue 에서 Message 를 가져와 msg.target.dispatchMessage(msg) 를 호출하여 Message 를 처리한다. ( tartget = handler )

자세한 내용은 Handler, Looper 의 구조에 대해 추가 포스팅하려 한다.

그럼 Message.obtain() 에 대해서 간략히 보았고 다음은 Handler.obtainMessage() 에 대해 보면서 서로 간 차이점을 점층적으로 분석해 보자.

Handler.obtainMessage()

마찬가지로 Android Developers 문서를 보자.

obtainMessage

public final Message obtainMessage()

Returns a new Message from the global message pool. More efficient than creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this). If you don't want that facility, just call Message.obtain() instead.

Global Message Pool 에서 새 Message 를 반환한다. 새 인스턴스를 생성하고 할당하는 것 보다 더 효율적이다. 검색된 Message 에는 Message 의 Hander 가 설정되어있다. (Message.target == this) 만약 그것을 원하지 않는다면 Message.obtain() 을 대신 사용하라.

이것 또한 global message pool 에서 새 message 객체를 반환한다고 설명하고 있다.

코드 상에서 다른 점을 살펴보자.

 public final Message obtainMessage()
{
return Message.obtain(this);
}
Handler.obtainMessage() 에서 Message.obtain() 의 결과를 리턴하고 있는걸 볼 수 있다.

this 로 Handler 자신을 파라미터로 넘겨주고 있는데, 이번에는 Message.obtain(Handelr handler) 의 코드를 보자.

public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;

return m;
}

Message.obtain() 으로 가져온 Message 객체에 target handler 를 전달 받은 handler 로 지정하는 것을 볼 수 있다.

이 코드를 보고 나니 Android Developers 문서 설명이 이해가 된다.

검색된 Message 에는 Message 의 Handler 가 설정되어있다.

이제 알게된 내용을 정리해보자. Message.obtain(), Handler.obtainMessage() 모두 global Message Pool 에서 재활용 되는 새 Message 객체를 받아온다.

다른 점은 Handler.obtainMessage() 는 호출하는 Handler 로 target hander 가 지정된 Message 객체가 반환 된다는 것이다.

그런데 target handler 가 지정되면 무엇이 다른거지 ?

또 다시 구글링해보자.

obtain obtainMessage 를 키워드로 검색해 보았지만 좋은 글은 찾지 못하였다.

http://spatula.net/mt/blog/2015/02/androids-messageobtain-vs-handlerobtainmessage-from-safeasynctask.html

분석해 놓은 글을 하나 찾았지만 명확히 이해가 되지 않았고 참고를 위해 적어 두어야겠다.

검색결과 많은 의견이 Handler.obtainMessage() 를 쓰라는 것이 많았다.

이유에 대해서는 추후 더 조사해보도록 해야겠다.

References

http://androidxref.com/4.4.2_r1/xref/frameworks/base/core/java/android/os/Message.java#106

https://developer.android.com/reference/kotlin/android/os/Message?hl=en#obtain()

http://spatula.net/mt/blog/2015/02/androids-messageobtain-vs-handlerobtainmessage-from-safeasynctask.html

https://stackoverflow.com/questions/49940878/when-message-object-is-recycled-by-android-an-android-system/49941095


반응형
공지사항
최근에 올라온 글