Handler 메시지 메커니즘 해석
Android는 UI를 업데이트하는 일련의 메커니즘을 제공하며 메시지를 보내고 처리할 수 있는 메시징 메커니즘을 제공합니다.
Handler
Handler 대상이 Looper와 소통하여push의 새로운 소식을 MessageQueue에 전달하도록 합니다.또는 Message Queue에서 Looper가 체크 아웃한 메시지를 받습니다.
메서드
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
myLooper()
.현재 Looper 대상을 가져오고 looper를 통해MessageQueue를 가져오며handler와 looper의 연결을 완료합니다 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
null
이면 이상을 던지고, 그렇지 않으면 대기열에 메시지를 넣습니다. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
메시지를 넣을 때 목표를 지정하고 기본적으로 자신을 보냅니다.
메시지를 대기열에 넣으면 Looper가
looper()
를 통해 메시지 대기열을 처리합니다. /**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
handleCallback
방법을 호출합니다내부 커넥터
Callback
public interface Callback {
public boolean handleMessage(Message msg);
}
Looper
이 스레드의 MessageQueue (메시지 대기열) 를 관리하기 위해 로퍼 대상만 생성할 수 있습니다.
MessageQueue
이 포함되어 있으며 모든handler가 보낸 메시지가 이 대기열을 통과합니다.MessageQueue
에서Message를 추출하고 있으면 처리하고 없으면 막는다 private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
Looper
를 만듭니다. 한 라인에 로퍼가 있으면 오류가 발생하고, 없으면 개인 구조 방법으로 새 Looper
를 만듭니다. private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
MessageQueue
및 현재 연결 Thread
myLopper()
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
현재 Looper 객체를 가져옵니다.
myQueue()
/**
* Return the {@link MessageQueue} object associated with the current
* thread. This must be called from a thread running a Looper, or a
* NullPointerException will be thrown.
*/
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
Looper에서 MessageQueue 가져오기
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
Looper
를 가져와서 현재 메시지 대기열을 가져오고, 메시지 대기열의 next()
방법으로 메시지를 가져옵니다.null이 아닐 때handler의 dispatchMessage(msg)
방법을 사용합니다.MessageQueue 메시지 대기열
메시지 저장 컨테이너
ThreadLocal class
역할: 라인에 정보 변수를 저장합니다.thread와 looper 사이의 관계를 책임진다
메서드
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
키 값 쌍의 형식은 Thread와 Looper 간의 관계를 저장하고 Thread는 키이고 Looper는 값이다
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
현재 라인에 대응하는 looper를 꺼냅니다.
내부 클래스 Values
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.