Ви можете краще зрозуміти, що Looper є в контексті GUI. Петля зроблена для того, щоб робити 2 речі.
1) Looper перетворює звичайний потік , який припиняється, коли його метод run () повертається, у щось, що працює постійно, поки не запущено додаток Android , що потрібно в рамках GUI (Технічно він все ще припиняється при поверненні методу run (). Але дозвольте мені уточнити, що я маю на увазі нижче).
2) Looper забезпечує чергу, в якій виконуються завдання, які потрібно виконати, що також потрібно в рамках GUI.
Як ви можете знати, коли запускається програма, система створює потік виконання програми, який називається "основний", а програми Android зазвичай повністю працюють на одному потоці за замовчуванням "основний потік". Але головна нитка - це не якась секретна, спеціальна нитка . Це просто звичайний потік, подібний до потоків, які ви створюєте з 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говорить: "За замовчуванням для потоків повідомлень не пов’язана цикла повідомлень", а Looper - це клас, "який використовується для запуску циклу повідомлень для потоку". Тепер ви можете зрозуміти, що це означає.
Щоб зробити речі більш зрозумілими, давайте перевіримо код, куди перетворюється головний потік. Все це відбувається в класі ActivityThread . У його основному () методі ви можете знайти код нижче, який перетворює звичайну основну нитку в щось те, що нам потрібно.
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, але всі GUI-системи можуть знадобитися дещо подібними до цього. Ви можете знайти майже такий же механізм у Java Swing Framework.