Я проверил официальный Android документации / руководство для Looper
, Handler
и MessageQueue
. Но я не мог этого понять. Я новичок в Android и очень запутался в этих концепциях.
Я проверил официальный Android документации / руководство для Looper
, Handler
и MessageQueue
. Но я не мог этого понять. Я новичок в Android и очень запутался в этих концепциях.
A Looper
- это цикл обработки сообщений: он читает и обрабатывает элементы из MessageQueue
. Looper
Класс, как правило , используется в сочетании с HandlerThread
(подкласс Thread
).
A Handler
- это служебный класс, который облегчает взаимодействие с a - в Looper
основном путем отправки сообщений и Runnable
объектов в поток MessageQueue
. Когда Handler
создается, он привязывается к определенному Looper
(и связанному потоку и очереди сообщений).
При типичном использовании вы создаете и запускаете, а HandlerThread
затем создаете Handler
объект (или объекты), с помощью которого другие потоки могут взаимодействовать с HandlerThread
экземпляром. Handler
Должны быть созданы во время работы на HandlerThread
, хотя после создания не существует никаких ограничений на то , что потоки могут использовать Handler
«ы методы планирования ( post(Runnable)
и т.д.)
Основной поток (он же поток пользовательского интерфейса) в приложении Android настраивается как поток-обработчик до создания экземпляра вашего приложения.
Помимо класса Docs, есть хорошая дискуссия все это здесь .
PS Все вышеперечисленные классы находятся в пакете android.os
.
MessageQueue
государства , чтоMessageQueue
является « класс низкого уровня , удерживающий список сообщений , которые будут ОтправляютсяLooper
. »Широко известно, что в Android незаконно обновлять компоненты пользовательского интерфейса непосредственно из потоков, отличных от основного потока . Этот документ Android ( Обработка дорогостоящих операций в потоке пользовательского интерфейса ) предлагает шаги, которые необходимо выполнить, если нам нужно запустить отдельный поток для выполнения некоторых дорогостоящих работ и обновить пользовательский интерфейс после того, как это будет сделано. Идея состоит в том, чтобы создать объект Handler, связанный с основным потоком , и опубликовать в нем Runnable в соответствующее время. Это
Runnable
будет вызвано в основном потоке . Этот механизм реализован с помощью классов Looper и Handler .Looper
Класс поддерживает MessageQueue , который содержит список сообщений . Важным признаком Looper является то, что он связан с потоком, в которомLooper
создается . Эта ассоциация сохраняется навсегда и не может быть нарушена или изменена. Также обратите внимание, что поток не может быть связан более чем с однимLooper
. Чтобы гарантировать эту связь,Looper
она хранится в локальном хранилище потока и не может быть создана напрямую через конструктор. Единственный способ создать его - вызвать статический метод подготовкиLooper
. Метод подготовки сначала исследует ThreadLocalтекущего потока, чтобы убедиться, что с потоком еще не связан Looper. После обследования создается новыйLooper
и сохраняется в форматеThreadLocal
. ПодготовивLooper
, мы можем вызвать для него метод цикла, чтобы проверить наличие новых сообщений иHandler
разобраться с ними.Как видно из названия,
Handler
класс в основном отвечает за обработку (добавление, удаление, отправку) сообщений текущего потокаMessageQueue
.Handler
Экземпляр также связан с резьбой. Связывания между обработчиком и нити достигается с помощьюLooper
иMessageQueue
.Handler
Будет всегда привязан кLooper
, и впоследствии связывается с нитью , связанной сLooper
. В отличие от этогоLooper
, несколько экземпляров Handler могут быть привязаны к одному потоку. Каждый раз, когда мы вызываем post или другие подобные методы вHandler
, новое сообщение добавляется в связанныйMessageQueue
. В поле назначения сообщения устанавливается текущийHandler
экземпляр. КогдаLooper
Получив это сообщение, он вызывает dispatchMessage в целевом поле сообщения, чтобы сообщение возвращалось к экземпляру Handler для обработки, но в правильном потоке. Отношения междуLooper
,Handler
иMessageQueue
как показано ниже:источник
Начнем с лупера. Вы сможете легче понять взаимосвязь между Looper, Handler и MessageQueue, если поймете, что такое Looper. Также вы можете лучше понять, что такое Looper в контексте графического интерфейса. Looper предназначен для двух вещей.
1) Looper преобразует обычный поток , который завершается, когда его
run()
метод возвращается, во что-то, что работает непрерывно, пока не будет запущено приложение Android , что необходимо в среде графического интерфейса (технически, он все еще завершается, когдаrun()
метод возвращается. Но позвольте мне пояснить, что я имею в виду, ниже).2) Looper предоставляет очередь, в которой задачи, которые необходимо выполнить, ставятся в очередь, что также необходимо в среде графического интерфейса.
Как вы, возможно, знаете, когда приложение запускается, система создает поток выполнения для приложения, называемый «основным», и приложения Android обычно выполняются полностью в одном потоке, по умолчанию это «основной поток». Но главный поток - это не какой-то секрет, особый поток . Это просто обычный поток, который вы также можете создать с помощью
new Thread()
кода, что означает, что он завершается, когдаrun()
возвращается его метод! Подумайте о приведенном ниже примере.Теперь давайте применим этот простой принцип к Android-приложению. Что произойдет, если приложение Android будет запущено в обычном потоке? Поток под названием «основной» или «UI» или что-то еще запускает приложение и рисует весь UI. Итак, пользователям открывается первый экран. И что теперь? Основной поток завершается? Нет, не должно. Он должен подождать, пока пользователи что-то сделают, верно? Но как добиться такого поведения? Что ж, мы можем попробовать с
Object.wait()
илиThread.sleep()
. Например, основной поток завершает свою начальную работу по отображению первого экрана и засыпает. Он просыпается, что означает прерывание, когда выбирается новое задание. Пока все хорошо, но на данный момент нам нужна структура данных, подобная очереди, для хранения нескольких заданий. Подумайте о случае, когда пользователь последовательно касается экрана, и задача занимает больше времени для завершения. Итак, нам нужна структура данных, чтобы удерживать задания, которые должны выполняться в порядке очереди. Кроме того, вы можете себе представить, что реализация потока с постоянным запуском и обработкой задания по прибытии с использованием прерывания непроста и приводит к сложному и часто не поддерживаемому коду. Мы бы предпочли создать новый механизм для этой цели, и в этом вся суть Looper . Официальный документ класса Looperговорит: «По умолчанию потоки не имеют связанного с ними цикла сообщений», а Looper - это класс, «используемый для запуска цикла сообщений для потока». Теперь вы можете понять, что это значит.Перейдем к Handler и MessageQueue. Во-первых, MessageQueue - это очередь, о которой я упоминал выше. Он находится внутри Looper, вот и все. Вы можете проверить это с помощью исходного кода класса Looper . Класс Looper имеет переменную-член MessageQueue.
Тогда что такое Хэндлер? Если есть очередь, то должен быть метод, который позволит нам поставить новую задачу в очередь, верно? Это то, что делает Хэндлер. Мы можем поставить новую задачу в очередь (MessageQueue), используя различные
post(Runnable r)
методы. Вот и все. Это все о Looper, Handler и MessageQueue.Мое последнее слово: в основном Looper - это класс, созданный для решения проблемы, возникающей в среде графического интерфейса. Но такого рода потребности могут возникнуть и в других ситуациях. На самом деле это довольно известный шаблон для многопоточного приложения, и вы можете узнать о нем больше в «Параллельном программировании на Java» Дуга Ли (особенно будет полезна глава 4.1.4 «Рабочие потоки»). Кроме того, вы можете себе представить, что этот вид механизма не является уникальным в структуре Android, но для всех платформ графического интерфейса может потребоваться что-то подобное. Вы можете найти почти такой же механизм в Java Swing framework.
источник
MessageQueue
: Это низкоуровневый класс, содержащий список сообщений, отправляемых aLooper
. Сообщения добавляются не напрямую в aMessageQueue
, а черезHandler
объекты, связанные сLooper
. [ 3 ]Looper
: Он перебирает a,MessageQueue
который содержит сообщения для отправки. Фактическая задача управления очередью выполняется агентом,Handler
который отвечает за обработку (добавление, удаление, отправку) сообщений в очереди сообщений. [ 2 ]Handler
: Это позволяет передавать и обрабатыватьMessage
иRunnable
объекты , связанные с потокаMessageQueue
. Каждый экземпляр Handler связан с одним потоком и очередью сообщений этого потока. [ 4 ]Когда вы создаете новый
Handler
, он привязывается к потоку / очереди сообщений потока, который его создает - с этого момента он будет доставлять сообщения и запускаемые файлы в эту очередь сообщений и выполнять их по мере выхода из очереди сообщений. .Пожалуйста, просмотрите изображение ниже [ 2 ] для лучшего понимания.
источник
Расширяя ответ @K_Anas, с примером, как указано
например, если вы попытаетесь обновить пользовательский интерфейс с помощью Thread.
ваше приложение выйдет из строя за исключением.
другими словами, вам нужно использовать
Handler
который сохраняет ссылку наMainLooper
ieMain Thread
илиUI Thread
и передает задачу какRunnable
.источник