Что такое Looper и Handler в Android
Что проверяют
Понимаете ли вы, как устроен главный поток Android: почему он не завершается, как в него попадает работа из других потоков и откуда берутся ANR и утечки. Следом просят написать свой поток с очередью.
Как отвечать
Схема из четырёх частей:
- MessageQueue: очередь сообщений потока, отсортированная по времени выполнения;
- Looper: бесконечный цикл, который достаёт сообщения из очереди и отдаёт на обработку. Не больше одного на поток, хранится в
ThreadLocal. СоздаётсяLooper.prepare(), запускаетсяLooper.loop(), повторныйprepare()бросает исключение; - Handler: вход в очередь конкретного Looper.
post(),postDelayed(),sendMessage()кладут работу в очередь,handleMessage()выполняет её в потоке этого Looper; - Message: единица работы с полями
what,arg1,obj. Берётся из пула черезMessage.obtain()илиobtainMessage(), а не черезnew.
Looper главного потока готовит фреймворк в ActivityThread.main(), поэтому Looper.getMainLooper() есть всегда. Через него идут колбэки, отрисовка и ввод. Если колбэк занял поток надолго, очередь стоит, и после 5 секунд без реакции на ввод система показывает ANR.
Для фонового потока с очередью есть HandlerThread. Останавливают его через quitSafely(): он дорабатывает сообщения, чей срок уже наступил, а quit() выбрасывает всё.
Конструктор Handler() без аргументов устарел в API 30, Looper передают явно: Handler(Looper.getMainLooper()). В новом коде чаще корутины, но Dispatchers.Main внутри построен на Handler главного Looper.
Где спотыкаются
Создают Handler анонимным классом в Activity и шлют postDelayed на минуту вперёд. Сообщение держит Handler, тот держит Activity, и после поворота экрана старая Activity не собирается. Лечится removeCallbacksAndMessages(null) в onDestroy().
Думают, что Handler создаёт фоновый поток. Он только отправляет работу в поток своего Looper, и тяжёлый код в post() на главном Looper всё так же блокирует UI.
Считают, что postDelayed() отмеряет реальное время. Задержка идёт по SystemClock.uptimeMillis(), который стоит в глубоком сне, поэтому для точных сроков нужен AlarmManager или WorkManager.