Я проверил официальную документацию/руководство Android для Looper
, Handler
и MessageQueue
. Но я не мог этого понять. Я новичок в 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
:
Ответ 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 - это цикл сообщений или очередь сообщений, которая в основном содержит список сообщений или 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) поставить в очередь действие, которое будет выполнено в другом потоке, чем ваш собственный. Другими словами, поставьте в очередь действие для выполнения в другом потоке.