Обработчики, MessageQueue, Looper, все ли они работают в streamе пользовательского интерфейса?

Я пытаюсь обернуть голову streamами, и я знаю, что я могу использовать Handler для отправки сообщений / runnables в MessageQueue , который, в свою очередь, подбирается Looper и отправляется обратно обработчику для обработки.

Если я отправляю обработчик в своей деятельности, MessageQueue ли Activity , Handler , MessageQueue и Looper все в streamе пользовательского интерфейса? Если нет, может кто-нибудь объяснить, как все это объединяется? 🙂

    Короткий ответ: все они работают по одной теме. Если они созданы из обратного вызова жизненного цикла Activity , все они запускаются в основном streamе пользовательского интерфейса.

    Длительный ответ:

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

    Вызов loop() обычно не возвращается в течение некоторого времени, но продолжает принимать сообщения («задачи», «команды» или все, что вам нравится их вызывать) из MessageQueue и обрабатывает их по отдельности (например, путем вызова обратно Runnable в сообщении). Когда в очереди нет сообщений, stream блокируется до появления новых сообщений. Чтобы остановить Looper , вам нужно вызвать quit() на нем (что, вероятно, не сразу останавливает цикл, а скорее устанавливает закрытый флаг, который периодически проверяется из цикла, сигнализируя о его остановке).

    Однако вы не можете напрямую добавлять сообщения в очередь. Вместо этого вы регистрируете MessageQueue.IdleHandler для ожидания обратного вызова queueIdle() , в котором вы можете решить, хотите ли вы чего-то или нет. Все обработчики вызываются поочередно. (Таким образом, «очередь» на самом деле не очередь, но вместо этого набор обратных вызовов будет вызываться регулярно .)

    Замечание относительно предыдущего абзаца: Это я догадывался. Я не мог найти никакой документации по этому поводу, но это имело бы смысл.

    обновление: см. комментарий ahcox и его ответ .

    Поскольку это большая работа, структура обеспечивает class Handler для упрощения . Когда вы создаете экземпляр Handler , он (по умолчанию) привязан к Looper уже прикрепленному к текущему streamу. ( Handler знает, к чему привязать Looper потому что раньше мы вызывали prepare() , который, вероятно, сохранил ссылку на Looper в ThreadLocal .)

    С помощью Handler вы можете просто вызвать post() чтобы «поместить сообщение в очередь сообщений streamа» (так сказать). Handler позаботится обо всех IdleHandler обратного вызова IdleHandler и убедится, что вы выполнили свой Runnable . (Он также может проверить, правильно ли это время, если вы отправили с задержкой.)

    Просто для того, чтобы быть ясным: единственный способ на самом деле сделать stream циклов сделать что-то, чтобы отправить сообщение в его цикл. Это действует до тех пор, пока вы не назовете quit () на петлере.


    Что касается streamа пользовательского интерфейса Android: в какой-то момент (возможно, до того, как будут созданы какие-либо действия и т. Д.), В инфраструктуре был создан Looper (содержащий MessageQueue ) и запустил его. С этого момента все, что происходит в streamе пользовательского интерфейса, проходит через этот цикл. Это включает в себя управление жизненным циклом деятельности и т. Д. Все обратные вызовы, которые вы переопределите ( onCreate() , onDestroy() …), по крайней мере, опосредованно отправляются из этого цикла. Вы можете увидеть это, например, в трассировке стека исключения. (Вы можете попробовать, просто напишите int a = 1 / 0; onCreate() где-то в onCreate() …)


    Я надеюсь в этом есть смысл. Извините за то, что ранее неясно.

    Продолжайте обсуждать вопрос «как все это вместе». Как писал user634618, петлератор берет на себя stream, основной stream пользовательского интерфейса в случае основного Looper .

    • Looper.loop() выводит сообщения из очереди сообщений. Каждое сообщение имеет ссылку на связанного обработчика, чтобы он возвращался (член-мишень).
    • Внутри Looper.loop() для каждого сообщения, полученного из очереди:
      • loop() вызывает public void Handler.dispatchMessage(Message msg) используя обработчик, который хранится в сообщении в качестве его целевого члена.
      • Если сообщение содержит элемент обратного вызова Runnable, который запускается.
      • Иначе, если обработчик имеет общий набор обратных вызовов, который запускается.
      • Else, Handler handleMessage() вызывается с сообщением в качестве аргумента. (Обратите внимание, что если вы выполняете обработчик подclassа как AsyncTask, вы можете переопределить handleMessage() как он есть.)

    В вопросе о том, что все объекты совместной работы находятся в одном и том же streamе пользовательского интерфейса, Handler должен быть создан в том же streamе, что и Looper который он будет отправлять сообщения. Его конструктор будет искать текущий Looper и хранить его как члена, привязывая Handler к этому Looper . Он также будет ссылаться на очередь сообщений Looper непосредственно в своем собственном элементе. Handler может использоваться для отправки работы Looper из любого streamа, но это идентификация очередей сообщений направляет работу, которая должна выполняться в streamе Looper .

    Когда мы запускаем некоторый код в другом streamе и хотим отправить Runnable для выполнения в streamе пользовательского интерфейса, мы можем сделать это следующим образом:

     // h is a Handler that we constructed on the UI thread. public void run_on_ui_thread(final Handler h, final Runnable r) { // Associate a Message with our Handler and set the Message's // callback member to our Runnable: final Message message = Message.obtain(h, r); // The target is the Handler, so this asks our Handler to put // the Message in its message queue, which is the exact same // message queue associated with the Looper on the thread on // which the Handler was created: message.sendToTarget(); } 

    Я пытаюсь реализовать этот интерфейс сам, чтобы понять концепцию. По простоте просто используйте интерфейс по необходимости. Вот мой тестовый код:

     import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class TestLooper { public static void main(String[] args) { UIThread thread = new UIThread(); thread.start(); Handler mHandler = new Handler(thread.looper); new WorkThread(mHandler, "out thread").run(); } } class Looper { private BlockingQueue message_list = new LinkedBlockingQueue(); public void loop() { try { while (!Thread.interrupted()) { Message m = message_list.take(); m.exeute(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void insertMessage(Message msg) { message_list.add(msg); } } class Message { String data; Handler handler; public Message(Handler handler) { this.handler = handler; } public void setData(String data) { this.data = data; } public void exeute() { handler.handleMessage(this); } } class Handler { Looper looper; public Handler(Looper looper) { this.looper = looper; } public void dispatchMessage(Message msg) { System.out.println("Handler dispatchMessage" + Thread.currentThread()); looper.insertMessage(msg); } public Message obtainMessage() { return new Message(this); } public void handleMessage(Message m) { System.out.println("handleMessage:" + m.data + Thread.currentThread()); } } class WorkThread extends Thread { Handler handler; String tag; public WorkThread(Handler handler, String tag) { this.handler = handler; this.tag = tag; } public void run() { System.out.println("WorkThread run" + Thread.currentThread()); Message m = handler.obtainMessage(); m.setData("message " + tag); handler.dispatchMessage(m); } } class UIThread extends Thread { public Looper looper = new Looper(); public void run() { //create handler in ui thread Handler mHandler = new Handler(looper); new WorkThread(mHandler, "inter thread").run(); System.out.println("thead run" + Thread.currentThread()); looper.loop(); } } 

    Если я отправляю обработчик в своей деятельности, работают ли Activity, Handler, MessageQueue и Looper все в streamе пользовательского интерфейса? Если нет, может кто-нибудь объяснить, как все это объединяется? 🙂

    Это зависит от того, как вы создаете обработчик

    Дело 1:

     Handler() 

    Конструктор по умолчанию связывает этот обработчик с Looper для текущего streamа.

    Если вы создаете Handler как это в streamе пользовательского интерфейса, Handler связан с Looper of UI Thread. MessageQueue также связан с Looper с MessageQueue пользовательского интерфейса.

    Случай 2:

     Handler (Looper looper) 

    Используйте предоставленный Looper вместо стандартного.

    Если я создаю HandlerThread и передаю Looper HandlerThread для обработчика, Handler и Looper связаны с HandlerThread, а не с streamом пользовательского интерфейса. Handler , MessageQueue и Looper связаны с HandlerThread .

    Случай использования: вы хотите выполнить операцию «Сеть или ввод-вывод». Вы не можете выполнить его в HandlerThread пользовательского интерфейса, и поэтому HandlerThread вам удобен.

      HandlerThread handlerThread = new HandlerThread("NetworkOperation"); handlerThread.start(); Handler requestHandler = new Handler(handlerThread.getLooper()); 

    Если вы хотите передать данные из HandlerThread в stream пользовательского интерфейса, вы можете создать еще один обработчик (скажем, responseHandler) с Looper из sendMessage пользовательского интерфейса и вызвать sendMessage . responseHandler пользовательского интерфейса Handler должен переопределить handleMessage

    Более подробную информацию см. В этих сообщениях.

    Какова цель Лупера и как его использовать? (Для понятий)

    Android: Тост в streamе (например, код, связав все эти понятия)

    Interesting Posts

    Могу ли я умножить строки на Java для повторения последовательностей?

    Как профилировать использование памяти и производительность с помощью инструментов?

    Квадратная компоновка GridLayoutManager для RecyclerView

    Использование CPU VirtualBox 100% на хосте

    Длинные команды, разделенные на несколько строк в пакетном (.bat) файле Windows Vista

    OnItemCLickListener не работает в listview

    Как преобразовать ASCII-код (0-255) в строку связанного символа?

    Проверка на нуль до отправки события … streamобезопасная?

    Безопасная строка для преобразования BigDecimal

    Очистка и настройка домашнего приложения по умолчанию

    Если async-wait не создает никаких дополнительных streamов, то как это реагирует на приложения?

    Как удалить учетную запись из приложения Mail в Windows 8?

    Есть ли смысл в установке антивируса на Ubuntu?

    Как запустить стеклянную рыбку 4 на порт 80 вместо 8080? root-доступ не является проблемой

    Несколько classов CSS: свойства Перекрытие на основе определенного порядка

    Давайте будем гением компьютера.