Какова связь между Looper, Handler и MessageQueue в Android?

Я проверил официальную документацию/руководство Android для Looper, Handler и MessageQueue. Но я не мог этого понять. Я новичок в android и очень смущен этими понятиями.

Ответ 1

Looper - это цикл обработки сообщений: он читает и обрабатывает элементы из MessageQueue. Класс Looper обычно используется вместе с HandlerThread (подкласс Thread).

Handler - это служебный класс, который облегчает взаимодействие с Looper главным образом путем публикации сообщений и объектов Runnable в потоке MessageQueue. Когда создается Handler, он привязывается к определенному Looper (и связанному потоку и очереди сообщений).

При обычном использовании, создании и начать HandlerThread, а затем создать Handler объект (или объекты), с помощью которого другие потоки могут взаимодействовать с HandlerThread экземпляра. Handler должен быть создан во время работы на HandlerThread, хотя после его создания нет никаких ограничений на то, какие потоки могут использовать методы планирования Handler (post(Runnable) и т.д.)

Основной поток (он же поток пользовательского интерфейса) в приложении Android настраивается как поток-обработчик перед созданием экземпляра приложения.

Помимо класса документации, там хорошая дискуссия все это здесь.

PS Все классы, упомянутые выше, находятся в пакете android.os.

Ответ 2

Общеизвестно, что это незаконно обновлять компоненты пользовательского интерфейса напрямую из потоков, отличных от основного потока в android. Этот документ android (Обработка дорогостоящих операций в потоке пользовательского интерфейса) предлагает следующие шаги, если нам нужно запустить отдельный поток, чтобы сделать несколько дорогостоящая работа и обновить интерфейс после его завершения. Идея состоит в создании объекта Handler, связанного с основным потоком, и отправьте Runnable в соответствующее время. Этот Runnable будет вызываться в главном потоке . Этот механизм реализован с помощью Looper и Handler классы.

Класс Looper поддерживает MessageQueue, который содержит список сообщения. Важным характером Looper является то, что он связан с потоком , в котором создается Looper. Эта связь хранится вечно и не может быть нарушена или изменена. Также обратите внимание, что поток не может быть связан с более чем одним Looper. Чтобы гарантировать эту ассоциацию, Looper хранится в потоковом локальном хранилище и не может быть создан через его конструктор напрямую. Единственный способ создать его - вызвать prepare статический метод на Looper. метод подготовки сначала рассматривает ThreadLocal текущего потока, чтобы убедиться, что Looper не связан с потоком. После экзамена создается новый Looper и сохраняется в ThreadLocal. Подготовив Looper, мы можем вызвать метод loop для проверки новых сообщений и иметь Handler для решения этих проблем.

Как видно из названия, класс Handler в основном отвечает за обработку (добавление, удаление, диспетчеризация) сообщений текущего потока MessageQueue. Экземпляр Handler также связан с потоком. привязка между обработчиком и потоком достигается с помощью Looper и MessageQueue. A Handler всегда привязан к a Looper, а затем привязан к потоку, связанному с, с Looper. В отличие от Looper, несколько экземпляров Handler могут быть привязаны к одному и тому же потоку. Всякий раз, когда мы вызываем post или любые методы, подобные в Handler, новое сообщение добавляется к связанному MessageQueue. Целевому полю сообщения присваивается текущий экземпляр Handler. Когда Looper получил это сообщение, он вызывает dispatchMessage в поле назначения сообщения, чтобы сообщение возвращалось к экземпляру Handler, чтобы обрабатываться, но на правильной нити. Ниже показаны отношения между Looper, Handler и MessageQueue:

enter image description here

Ответ 3

Давайте начнем с Looper. Вы сможете легче понять отношения между Looper, Handler и MessageQueue, когда поймете, что такое Looper. Также вы можете лучше понять, что такое Looper в контексте графического интерфейса. Looper сделан, чтобы сделать 2 вещи.

1) Looper преобразует обычный поток, который завершается, когда возвращается его метод run(), во что-то, что работает непрерывно до запуска приложения Android, что необходимо в среде графического интерфейса пользователя (Технически, он все еще завершается, когда возвращается метод run(). Но пусть поясните мне, что я имею в виду, ниже).

2) Looper предоставляет очередь, в которой выполняются задания, которые также необходимы в среде GUI.

Как вы, возможно, знаете, когда приложение запускается, система создает поток выполнения для приложения, называемый "основным", и приложения Android обычно запускаются полностью в одном потоке по умолчанию "основной поток". Но главная нить не какая-то секретная, особая нить. Это просто обычный поток, который вы также можете создать с new Thread() кодом new Thread(), что означает, что он завершается, когда возвращается его метод run() ! Подумайте о приведенном ниже примере.

public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }

    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}

Теперь давайте применим этот простой принцип к приложению Android. Что произойдет, если приложение Android будет запущено в обычном потоке? Поток с именем "main" или "UI" или чем-то еще запускает приложение и рисует весь интерфейс. Итак, первый экран отображается для пользователей. И что теперь? Основной поток заканчивается? Нет, не должно. Следует подождать, пока пользователи что-то сделают, верно? Но как мы можем достичь этого поведения? Ну, мы можем попробовать с Object.wait() или Thread.sleep(). Например, основной поток завершает свою начальную работу для отображения первого экрана и спит. Он пробуждается, что означает прерывание, когда выбирается новая работа. Пока все хорошо, но в данный момент нам нужна структура данных, похожая на очередь, для хранения нескольких заданий. Подумайте о случае, когда пользователь касается экрана последовательно, и выполнение задачи занимает больше времени. Итак, нам нужна структура данных для хранения заданий, которые должны выполняться в порядке "первым пришел - первым вышел". Кроме того, вы можете себе представить, что реализовать постоянно работающий поток и процесс-задание-при поступлении с использованием прерывания непросто, и это приводит к сложному и часто не поддерживаемому коду. Мы предпочли бы создать новый механизм для этой цели, и это то, что Лупер это все. Официальный документ класса Looper гласит: "С потоками по умолчанию не связан цикл сообщений", а Looper - это класс, "используемый для запуска цикла сообщений для потока". Теперь вы можете понять, что это значит.

Давайте перейдем к Handler и MessageQueue. Во-первых, MessageQueue - это очередь, о которой я упоминал выше. Он находится внутри Looper, и это он. Вы можете проверить это с помощью исходного кода класса Looper. У класса Looper есть переменная-член MessageQueue.

Тогда что такое хендлер? Если есть очередь, то должен быть метод, который позволит нам ставить в очередь новую задачу, верно? Это то, что делает Handler. Мы можем поставить новую задачу в очередь (MessageQueue), используя различные методы post(Runnable r). Это. Это все о Looper, Handler и MessageQueue.

Мое последнее слово, так что в основном Looper - это класс, созданный для решения проблемы, возникающей в среде GUI. Но такого рода потребности могут возникнуть и в других ситуациях. На самом деле это довольно известный шаблон для многопоточного приложения, и вы можете узнать о нем больше в "Параллельном программировании на Java" Дуга Ли (особенно было бы полезно, глава 4.1.4 "Рабочие потоки"). Кроме того, вы можете себе представить, что этот тип механизма не уникален в платформе Android, но все графические интерфейсы могут нуждаться в некотором сходстве с этим. Вы можете найти почти такой же механизм в Java Swing Framework.

Ответ 4

MessageQueue: Это класс низкого уровня, содержащий список сообщений, отправляемых с помощью Looper. Сообщения не добавляются непосредственно к MessageQueue, а скорее через объекты Handler, связанные с Looper. [3]

Looper: он перемещается по MessageQueue, который содержит отправленные сообщения. Фактическая задача управления очередью выполняется Handler, которая отвечает за обработку (добавление, удаление, диспетчеризация) сообщений в очереди сообщений. [2]

Handler: он позволяет отправлять и обрабатывать объекты Message и Runnable, связанные с потоком MessageQueue. Каждый экземпляр Handler связан с одним потоком и этой очереди сообщений потока. [4]

Когда вы создаете новый Handler, он привязан к очереди потоков/сообщений потока, который его создает, - с этой точки он будет доставлять сообщения и runnables в очередь сообщений и выполнять их при выходе из очереди сообщений.

Пожалуйста, просмотрите изображение ниже [2] для лучшего понимания.

введите описание изображения здесь

Ответ 5

MessageQueue, Handler, Looper in Android MessageQueue:

MessageQueue - это цикл сообщений или очередь сообщений, которая в основном содержит список сообщений или Runnables (набор исполняемого кода).

Другими словами, MessageQueue - это очередь, в которой есть задачи, называемые сообщениями, которые должны быть обработаны.

Примечание. Android поддерживает MessageQueue в основном потоке.

Looper:

Looper - это работник, который обслуживает MessageQueue для текущего потока. Looper проходит по очереди сообщений и отправляет сообщения соответствующим обработчикам для обработки.

Любой поток может иметь только один уникальный Looper, это ограничение достигается с помощью концепции хранилища ThreadLocal.

Преимущества Looper и MessageQueue

Есть некоторые преимущества использования Looper и MessageQueue, как описано below-

· С использованием MessageQueue выполнение является последовательным, поэтому в случае параллельных потоков это позволит избежать условий гонки.

· Обычно поток не может быть повторно использован после завершения его работы. Но поток с Looper сохраняется, пока вы не вызовете метод quit, поэтому вам не нужно создавать новый экземпляр каждый раз, когда вы хотите запустить задание в фоновом режиме.

Обработчик:

Обработчик позволяет связаться с потоком пользовательского интерфейса из другого фонового потока. Это полезно в Android, так как Android не позволяет другим потокам напрямую взаимодействовать с потоком пользовательского интерфейса.

Обработчик позволяет отправлять и обрабатывать объекты Message и Runnable, связанные с потоками MessageQueue. Каждый экземпляр обработчика связан с одним потоком и с этой очередью сообщений потока.

Когда вы создаете новый обработчик, он привязывается к потоку/очереди сообщений потока, который его создает - с этого момента он будет доставлять сообщения и исполняемые файлы в эту очередь сообщений и выполнять их по мере их выхода из очереди сообщений.,

Существует два основных варианта использования обработчика:

(1) Чтобы запланировать выполнение сообщений и исполняемых файлов в будущем. Другими словами, выполните действия в том же потоке в будущем.

(2) поставить в очередь действие, которое будет выполнено в другом потоке, чем ваш собственный. Другими словами, поставьте в очередь действие для выполнения в другом потоке.