Каковы отношения между Петлителем, обработчиком и MessageQueue в Android?

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

5 ответов


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

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

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

основной поток (a.к. a. UI thread) в Android-приложении настраивается как поток обработчика перед созданием экземпляра приложения.

помимо документов класса, есть хорошее обсуждение всего этого здесь.


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

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

как следует из названия,Handler класс в основном отвечает за обработку (добавление, удаление, отправку) сообщений текущего потока MessageQueue. А Handler экземпляр также привязан к нитка. The привязка между обработчиком и потоком достигается через Looper и MessageQueue. А Handler is всегда a Looper, а затем привязан к поток, связанный С Looper. В отличие от Looper, несколько экземпляров обработчика могут быть привязаны к одному потоку. Всякий раз, когда мы призываем в должности или любые методы, похожие на Handler новое сообщение добавляется в связанный MessageQueue. В поле сообщения имеет значение ток Handler экземпляра. Когда Looper получено это сообщение, оно вызывает dispatchMessage в целевом поле сообщения, чтобы сообщение возвращалось к экземпляру обработчика для обработки, но в правильном потоке. Отношения между Looper, Handler и MessageQueue показано ниже:

enter image description here


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

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

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

как вы знаете, при запуске приложения система создает поток выполнения для приложения, называемого "main" , а приложения Android обычно запускаются полностью в одном потоке по умолчанию " main нить." Но!--11-->основной поток не какой-то секрет, специальный поток. Это просто обычный поток, который вы также можете создать с помощью 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 app. Что произойдет, если приложение Android запускается в обычном потоке? Поток под названием "main" или " UI " или что-то еще запускает приложение и рисует весь пользовательский интерфейс. Итак, первый экран отображается на пользователи. И что теперь? Основной поток заканчивается? Нет, не должно. Это должно подождать, пока пользователи что-то не сделают, верно? Но как мы можем добиться такого поведения? Ну, мы можем попробовать с Object.wait() или Thread.sleep(). Например, основной поток завершает начальную работу для отображения первого экрана и спит. Он просыпается, что означает прерывание, когда новая работа выполняется. Пока все хорошо, но на данный момент нам нужна структура данных в виде очереди для выполнения нескольких заданий. Подумайте о случае, когда пользователь касается экрана серийно, и задача занимает больше времени, чтобы закончить. Итак, нам нужна структура данных для выполнения заданий, выполняемых в порядке "первый-в-первый-выход". Кроме того, вы можете себе представить, что реализация когда-либо запущенного и выполняемого потока с помощью прерывания нелегка и приводит к сложному и часто недостижимому коду. Мы предпочли бы создать новый механизм для этой цели, и вот что такое Looper. The официальный документ класса Looper говорит, "Потоки по умолчанию не имеют связанного с ними цикла сообщений", а Looper-это класс"используемый для запуска цикла сообщений для потока". Теперь вы можете понять, что это значит.

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

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

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


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

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

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

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

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

enter image description here


MessageQueue, Handler, Looper in Android объект messagequeue:

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

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

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

петлителя:

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

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

преимущества петлителя и MessageQueue

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

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

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

обработчик:

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

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

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

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

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

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