Как Looper знает, как отправить сообщение в Handler?
Вопрос в том, где я говорю моей теме использовать mHandler для Looper?
Спасибо. Я использую следующий код:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
3 ответа
Вопрос в том, где я говорю моей теме использовать mHandler для Looper?
Вам не нужно указывать это явно, потому что система (фреймворк) делает это за вас. Когда вы создаете Handler
, он автоматически получит доступ к очереди сообщений вашего текущего Thread
, Цитирую ваш комментарий:
Как система знает, чтобы отправить сообщение
mHandler
Handler
?
Я подробно опишу это ниже.
Это конструктор android.os.Handler
в Android:
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
Как видите, сначала он получает Looper
вашего текущего Thread
, Исходный код Looper.myLooper()
как следует:
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
Он получает его из локального хранилища потока. Позже, когда вы отправите Message
с этим Handler
, Handler
фактически устанавливает себя в качестве получателя Message
это как Looper
будет знать, куда отправить Message
когда это прибудет. Подробно:
Когда вы звоните mHandler.sendMessage()
в конечном итоге этот код выполняется (среди многих других строк кода):
MessageQueue queue = mQueue;
boolean sent = false;
if (queue != null) {
msg.target = this; // msg is your Message instance
sent = queue.enqueueMessage(msg, uptimeMillis);
}
Как видите, он устанавливает Handler
экземпляр как цель Message
, Итак, позже, когда Message
отправляется, он будет содержать Handler
как его цель. Вот как Looper
будет знать, какой Handler
он должен отправить его. Подробно, когда вы звоните Looper.loop()
следующее происходит для каждого из ваших Message
экземпляры в очереди:
msg.target.dispatchMessage(msg);
dispatchMessage()
код следующий:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Обратите внимание на последний handleMessage(msg)
звоните - это именно ваш handleMessage(msg)
переопределять!
Для лучшего понимания создайте нормальный Thread
и попробуйте создать Handler
в run()
метод этой темы. Вы получите RuntimeException
говоря:
Невозможно создать обработчик внутри потока, который не вызвал
Looper.prepare()
Теперь вызывая Looper.prepare() в run()
метод до создания Handler
создаст новый Looper
Объект, связанный с вызывающим потоком. Источник вашей путаницы в том, что Looper.prepare() не принимает Thread
в качестве аргумента. Это не нужно, так как это статический метод, который внутренне получает ThreadLocal
текущего запущенного потока. Там может быть не более одного Looper
связано с любым Thread
,
Теперь звоню new Handler()
ассоциирует новый Handler
объект с Looper
текущего Thread
внутренне позвонив Looper.myLooper()
, Вы можете создать более одного Handler
каждый со своим обратным вызовом в той же теме. Все обработчики будут получать свои сообщения из очереди сообщений одного и того же Looper
,
Вы ничего не говорите. От Handler
документация:
Каждый экземпляр обработчика связан с одним потоком и очередью сообщений этого потока. Когда вы создаете новый обработчик, он привязывается к потоку / очереди сообщений потока, который его создает - с этого момента он будет доставлять сообщения и исполняемые файлы в эту очередь сообщений и выполнять их по мере их выхода из очереди сообщений.,
Обработчик автоматически привязывается к очереди сообщений потока. Вы только реализуете обратный вызов, и система позаботится обо всем, то есть отправит и обработает сообщения. На самом деле я согласен, что, используя два статических метода, таких как Looper.prepare()
а также Looper.loop()
и автоматически выводит вещи, делает узор похожим на черную магию:)