Ответ
Handler и Looper работают вместе для обработки сообщений в потоке. Looper создает бесконечный цикл, который извлекает сообщения из очереди MessageQueue и передает их Handler'у для обработки.
Основные моменты:
- У каждого потока может быть только один Looper
- Handler привязан к Looper'у потока, в котором создан
- Handler отправляет сообщения в очередь Looper'а
Пример:
// Создаем Handler в главном потоке
val handler = Handler(Looper.getMainLooper())
// Отправляем сообщение
handler.post {
// Код выполнится в главном потоке
} Ответ 18+ 🔞
А, ну это ж классика, ебать мои старые костыли! Смотри, как это работает, чтобы мозг не взорвался.
Представь себе, что у тебя есть один чувак — Looper. Он сидит на своём потоке, как мартышлюшка на пальме, и делает только одно дело: бесконечно крутит хуй с винтом, то есть цикл. Его работа — тупо таскать сообщения из одной коробки, которая называется MessageQueue. Вытащил одно — отдал на обработку. Вытащил следующее — опять отдал. И так до скончания века, пока поток жив. И главное правило — на одном потоке может сидеть только один такой зануда-Looper. Два — уже пиздопроебибна, всё сломается.
А теперь смотри сюда. Есть второй персонаж — Handler. Это уже более хитрая жопа. Он привязывается к конкретному Looper'у, как пиявка. Создал ты Handler в главном потоке — он и прилепится к главному Looper'у. Создал в фоновом — будет работать с очередью фонового.
И вся магия в чём? Handler — это твой говорящий попугай. Ты через него можешь отправлять задания (Runnable) или сообщения (Message) прямиком в ту самую очередь Looper'а, к которому он привязан. А Looper, как добросовестный раб, вытащит твоё задание и выполнит его в своём потоке. Вот и весь фокус!
То есть, если ты в каком-нибудь фоновом потоке накодил, а тебе надо UI обновить (а UI можно трогать только из главного потока), ты что делаешь? Берёшь Handler, который привязан к главному Looper'у, и шлёшь ему команду: «Эй, братва на главной, нарисуй вот это!». И он это сделает. Безопасно. Красиво. Удивление пиздец, как просто.
Смотри на код, тут всё понятно:
// Берём Handler, который работает с очередью ГЛАВНОГО потока (Main Looper)
val handler = Handler(Looper.getMainLooper())
// Шлём ему дело в очередь
handler.post {
// А вот этот кусок кода выполнится уже точно в главном потоке.
// Можешь спокойно TextView тыкать, не боясь краша.
}
Вот и вся философия. Looper — это конвейер с одной лентой на поток. Handler — пульт управления этим конвейером. Хочешь что-то сделать в том потоке — найди его пульт (Handler) и нажми кнопку (post). Он сам всё доставит и выполнит. Ёпта, гениально и просто, как тапок.