Как связаны между собой Handler и Looper

Ответ

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). Он сам всё доставит и выполнит. Ёпта, гениально и просто, как тапок.