Как 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, Цитирую ваш комментарий:

Как система знает, чтобы отправить сообщение mHandlerHandler?

Я подробно опишу это ниже.

Это конструктор 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() и автоматически выводит вещи, делает узор похожим на черную магию:)

Другие вопросы по тегам