Я новичок в Android. Я хочу знать, что делает класс Looper
, а также как его использовать. Я прочитал Android документацию класса Looper, но я не могу это полностью понять.
Я видел это во многих местах, но не мог понять его цели. Может ли кто-нибудь помочь мне, определив цель Looper
, а также, если возможно, простой пример?
Какова цель Лупера и как его использовать?
Ответ 1
Что такое Looper?
Looper - это класс, который используется для выполнения сообщений (Runnables) в очереди. Обычные нити не имеют такой очереди, например. простой поток не имеет очереди. Он выполняется один раз и после завершения выполнения метода, поток не запускает другое сообщение (Runnable).
Где мы можем использовать класс Looper?
Если кто-то хочет выполнить несколько сообщений (Runnables), тогда он должен использовать класс Looper, который отвечает за создание очереди в потоке. Например, при написании приложения, которое загружает файлы из Интернета, мы можем использовать класс Looper для загрузки файлов в очередь.
Как это работает?
Существует метод prepare()
для подготовки Looper. Затем вы можете использовать метод loop()
для создания цикла сообщений в текущем потоке, и теперь ваш Looper готов выполнить запросы в очереди до тех пор, пока вы не выйдете из цикла.
Вот код, по которому вы можете подготовить Looper.
class LooperThread extends Thread {
public Handler mHandler;
@Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Ответ 2
Вы можете лучше понять, что такое Looper в контексте инфраструктуры GUI. 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" или чем-то еще, запускает ваше приложение и рисует весь UI. Итак, первый экран отображается для пользователей. И что теперь? Основной поток заканчивается? Нет, не должно. Следует подождать, пока пользователи что-то сделают, верно? Но как мы можем достичь этого поведения? Ну, мы можем попробовать с Object.wait()
или Thread.sleep()
. Например, основной поток завершает свою начальную работу для отображения первого экрана и спит. Он пробуждается, что означает прерванный, когда выбирается новая работа. Пока все хорошо, но в данный момент нам нужна структура данных в виде очереди для хранения нескольких заданий. Подумайте о случае, когда пользователь касается экрана последовательно, и выполнение задачи занимает больше времени. Таким образом, нам нужна структура данных для хранения заданий, выполняемых в порядке "первым пришел - первым вышел". Кроме того, вы можете себе представить, что реализовать поток, который постоянно выполняется и обрабатывает задание, когда поступает, используя прерывание, нелегко и приводит к сложному и часто не поддерживаемому коду. Мы бы предпочли создать новый механизм для этой цели, и это то, что Лупер это все. Официальный документ класса Looper гласит: "С потоками по умолчанию не связан цикл сообщений", а Looper - это класс, "используемый для запуска цикла сообщений для потока". Теперь вы можете понять, что это значит.
Чтобы сделать вещи более понятными, давайте проверим код, в котором преобразован основной поток. Все это происходит в классе ActivityThread. В его методе main() вы можете найти приведенный ниже код, который превращает обычный основной поток в то, что нам нужно.
public final class ActivityThread {
...
public static void main(String[] args) {
...
Looper.prepareMainLooper();
Looper.loop();
...
}
}
и Looper.loop()
зацикливается бесконечно и удаляет сообщение из очереди и обрабатывает по одному:
public static void loop() {
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
msg.target.dispatchMessage(msg);
...
}
}
Итак, в основном, Looper - это класс, созданный для решения проблемы, возникающей в среде GUI. Но такого рода потребности могут возникать и в других ситуациях. На самом деле это довольно известный шаблон для многопоточного приложения, и вы можете узнать о нем больше в "Параллельном программировании на Java" Дуга Ли (особенно было бы полезно, глава 4.1.4 "Рабочие потоки"). Кроме того, вы можете себе представить, что этот вид механизма не уникален в платформе Android, но все графические интерфейсы могут нуждаться в некоторой аналогии с этим. Вы можете найти почти такой же механизм в среде Java Swing.
Ответ 3
Looper позволяет выполнять задачи последовательно в одном потоке. И обработчик определяет те задачи, которые нам нужно выполнить. Это типичный сценарий, который я пытаюсь проиллюстрировать в этом примере:
class SampleLooper extends Thread {
@Override
public void run() {
try {
// preparing a looper on current thread
// the current thread is being detected implicitly
Looper.prepare();
// now, the handler will automatically bind to the
// Looper that is attached to the current thread
// You don't need to specify the Looper explicitly
handler = new Handler();
// After the following line the thread will start
// running the message loop and will not normally
// exit the loop unless a problem happens or you
// quit() the looper (see below)
Looper.loop();
} catch (Throwable t) {
Log.e(TAG, "halted due to an error", t);
}
}
}
Теперь мы можем использовать обработчик в некоторых других потоках (например, поток ui), чтобы выполнить задачу на Looper для выполнения.
handler.post(new Runnable()
{
public void run() {
//This will be executed on thread using Looper.
}
});
В потоке пользовательского интерфейса мы имеем неявный Looper, который позволяет обрабатывать сообщения в потоке ui.
Ответ 4
Android Looper
обертка прикрепить MessageQueue
к Thread
и управляет обработкой очереди. Это выглядит очень загадочно в документации Android, и часто мы можем столкнуться с проблемами доступа к пользовательскому интерфейсу Looper
. Если мы не понимаем основ, с этим становится очень трудно справиться.
Вот статья, которая объясняет жизненный цикл Looper
, как его использовать и как использовать Looper
в Handler
Looper = Thread + MessageQueue
Ответ 5
Определение Looper & Handler:
Looper - это класс, который превращает поток в поток конвейера, а обработчик предоставляет вам механизм для вставки задач в него из любых других потоков.
Подробности:
Таким образом, поток PipeLine - это поток, который может принимать больше задач из других потоков через обработчик.
Looper назван так, потому что он реализует цикл - берет следующую задачу, выполняет ее, затем берет следующую и так далее. Обработчик называется обработчиком, потому что он используется для обработки или принятия следующей задачи каждый раз из любого другого потока и передачи в Looper (Thread или PipeLine Thread).
Пример:
Отличным примером Looper and Handler или PipeLine Thread является загрузка нескольких изображений или загрузка их на сервер (Http) по одному в одном потоке вместо запуска нового потока для каждого сетевого вызова в фоновом режиме.
Узнайте больше здесь о Looper и Handler и определении Threading Thread:
Ответ 6
A Looper имеет synchronized
MessageQueue
, который использовался для обработки сообщений, помещенных в очередь.
Он реализует специальный шаблон хранения Thread
.
Только один Looper
за Thread
. Ключевыми методами являются prepare()
, loop()
и quit()
.
prepare()
инициализирует текущий Thread
как Looper
. prepare()
- это метод static
, который использует класс ThreadLocal
, как показано ниже.
public static void prepare(){
...
sThreadLocal.set
(new Looper());
}
-
prepare()
должен быть вызван явно перед запуском цикла событий. -
loop()
запускает цикл событий, который ожидает, что сообщения поступят в конкретный поток сообщений Thread. После получения следующего сообщения методloop()
отправляет сообщение его целевому обработчику -
quit()
отключает цикл событий. Он не завершает цикл, но вместо этого он вставляет специальное сообщение
Looper
можно запрограммировать в Thread
с помощью нескольких шагов
-
Расширить
Thread
-
Вызвать
Looper.prepare()
для инициализации Thread как aLooper
-
Создайте один или несколько
Handler
(s) для обработки входящих сообщений - Вызов
Looper.loop()
для обработки сообщений до тех пор, пока цикл не будет переданquit()
.
Ответ 7
Продолжительность жизни java Thread завершена после завершения метода run()
. Одну нить нельзя запустить снова.
Looper преобразует нормальный Thread
в цикл сообщения. Ключевыми методами Looper
являются:
void prepare ()
Инициализировать текущий поток в качестве петлителя. Это дает вам возможность создавать обработчики, которые затем ссылаются на этот петлитель, прежде чем начать цикл. Обязательно вызовите loop() после вызова этого метода и завершите его, вызвав quit().
void loop ()
Запустите очередь сообщений в этом потоке. Обязательно вызовите quit(), чтобы закончить цикл.
void quit()
Выход из петлителя.
Заставляет метод loop() завершаться без обработки каких-либо сообщений в очереди сообщений.
Эта статья статьи о мыслях от Janishar объясняет основные понятия красивым способом.
Looper
связан с потоком. Если вам нужно Looper
в потоке пользовательского интерфейса, Looper.getMainLooper()
вернет связанный поток.
Вам нужно Looper
связать с Handler.
Looper
, Handler
, а HandlerThread
- метод андроидов для решения задач асинхронного программирования.
Как только у вас есть Handler
, вы можете вызвать API ниже.
post (Runnable r)
Заставляет Runnable r добавляться в очередь сообщений. Runnable будет запущен в потоке, к которому прикреплен этот обработчик.
boolean sendMessage (Message msg)
Отбрасывает сообщение в конец очереди сообщений после всех ожидающих сообщений до текущего времени. Он будет получен в handleMessage (Message) в потоке, прикрепленном к этому обработчику.
HandlerThread - это удобный класс для запуска нового потока с петлевым механизмом. Затем петлитель можно использовать для создания классов обработчиков
В некоторых сценариях вы не можете запускать задачи Runnable
в потоке пользовательского интерфейса.
например Сетевые операции: отправить сообщение в сокет, открыть URL-адрес и получить контент, прочитав InputStream
В этих случаях полезно использовать HandlerThread
. Вы можете получить объект Looper
из HandlerThread
и создать Handler
на HandlerThread
вместо основного потока.
HandlerThread будет выглядеть следующим образом:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
См. ниже сообщение, например, код:
Ответ 8
Этот ответ не имеет никакого отношения к вопросу, но использование петлителя и способ создания человеком обработчика и петлителя во ВСЕХ ответах здесь - это плохая практика (некоторые объяснения верны, хотя), я должен опубликовать это:
HandlerThread thread = new HandlerThread(threadName);
thread.start();
Looper looper = thread.getLooper();
Handler myHandler = new Handler(looper);
и для полная реализация
Ответ 9
Обработка нескольких элементов вниз или загрузки в Service является лучшим примером.
Handler
и AsnycTask
часто используются для распространения событий/сообщений между пользовательским интерфейсом (thread) и рабочим потоком или с задержкой действий. Поэтому они больше связаны с пользовательским интерфейсом.
A Looper
обрабатывает задачи (Runnables, Futures) в связанной с потоком очереди в фоновом режиме - даже без взаимодействия пользователя или с отображаемым интерфейсом (приложение загружает файл в фоновом режиме во время разговора).
Ответ 10
Что такое Лупер?
ОТ ДОКУМЕНТОВ
Looper
Class используется для запуска цикла сообщений для thread
. По умолчанию потоки не имеют циклы сообщений, связанной с ними; чтобы создать его, вызовите prepare()
в потоке, который должен запустить цикл, а затем loop()
чтобы он обрабатывал сообщения до тех пор, пока цикл не будет остановлен.
-
Looper
- это цикл обработки сообщений: - Важным символом Looper является то, что он связан с потоком, в котором создается Looper
- Класс Looper поддерживает
MessageQueue
, который содержит список сообщений. Важным символом Looper является то, что он связан с потоком, в котором создается Looper. -
Looper
назван так, потому что он реализует цикл - берет следующую задачу, выполняет ее, затем берет следующую и так далее.Handler
называется обработчиком, потому что кто-то не может придумать лучшего имени - Android
Looper
- это класс Java в пользовательском интерфейсе Android, который вместе с классом Handler обрабатывает события пользовательского интерфейса, такие как нажатия кнопок, перерисовка экрана и переключение ориентации.
Как это устроено?
Создание Looper
MessageQueue
получает Looper
и MessageQueue
, вызывая Looper.prepare()
после своего запуска. Looper.prepare()
идентифицирует вызывающий поток, создает объект Looper и MessageQueue
и связывает поток
ОБРАЗЕЦ КОДА
class MyLooperThread extends Thread {
public Handler mHandler;
public void run() {
// preparing a looper on current thread
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
// this will run in non-ui/background thread
}
};
Looper.loop();
}
}
Для получения дополнительной информации проверьте ниже пост