Что произойдет, если обработчик отправит сообщение в поток после Looper.prepare(), но до вызова Looper.loop()?

Рассмотрим следующий фрагмент:

Looper.prepare();
handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            getLooper().quitSafely();
        }
    };
for(int i = 0; i < urls.size(); i++) {
    useCaseProvider.get().execute(callback, handler, urls.get(i), threadPool);
}
Looper.loop();

//Continue processing the results of all the use cases after the    
//loop has been asked to terminated via the handler

Немного фона: я делаю некоторую обработку в потоке пользовательского интерфейса, где мне нужно будет пинговать большое количество устройств и делать что-то с результатом. Мне нужно выполнить запросы параллельно, чтобы быть эффективными.

Вопрос: Если один из этих вариантов использования как-то выполнялся достаточно быстро и сделал обратный вызов, прежде чем я смог нанести удар Looper.loop(); было ли сообщение поставлено в очередь или просто потеряно? Обратные вызовы отправляются обратно в этот поток обработчиком, проводящим runnable в исходный поток.

Ответ 1

Предполагая, что вы вызвали Looper.prepare() до вашего использованияCaseProvider, доставляя результаты, вы должны быть в порядке. Если Looper.prepare не был вызван, вы должны видеть, что RuntimeException выбрано.

Объект Looper привязан к локальному потоку, в котором размещается очередь сообщений. Функция Looper.prepare построит эту очередь сообщений, после чего вы сможете начать массовое рассылку сообщений. Как только вы запустите Looper.loop(), когда эти ожидающие сообщения начнут выполнять.

Глядя на фрагмент, я не слишком уверен, как все связано. Как правило, вы хотите построить петлитель следующим образом:

private static final class MyThread extends Thread {
    private Handler mHandler;

    @Override
    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // handle message
            }
        };

        Looper.loop();
    }

    public Handler getHandler() {
        return mHandler;
    }
}

Я предполагаю, что ваш пул потоков - это пул потоков MyThread, каждый из которых имеет свой собственный Looper. Пул потоков должен инициализировать ваши потоки, поэтому, как только вы доставляете Runnable для выполнения вашим потоком, метод run() должен инициализировать Looper.

С другой стороны, если вы хотите связать свой обработчик с определенным петлером (т.е. вы не создаете обработчик в потоке, как описано выше), вы должны передать поток Looper в конструктор, например:

Handler h = new Handler(myLooperThread);

Если вы не указали это, тогда обработчик использует поток, в котором он был создан, чтобы захватить этот поток Looper из объекта ThreadLocal.

Наконец, если ваши намерения состоят в том, чтобы сообщения, доставленные на обработчике, связанные с потоком пользовательского интерфейса, вам не следует беспокоиться о вызове Looper.prepare или Looper.loop. Это обрабатывается Activity.