← Назад к вопросам
Как передать сообщение с одного потока на другой с помощью Handler и Looper?
2.0 Middle🔥 171 комментариев
#Android компоненты#Многопоточность и асинхронность
Комментарии (1)
🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как передать сообщение между потоками с помощью Handler и Looper
Основные понятия системы сообщений Android
Android использует систему сообщений для межпоточного взаимодействия. Основными компонентами этой системы являются:
- Looper - бесконечный цикл, который обрабатывает очередь сообщений (
MessageQueue) в потоке - Handler - интерфейс для отправки сообщений в очередь и их обработки
- Message - объект, содержащий данные для передачи
- MessageQueue - очередь сообщений, связанная с Looper
Создание и настройка потока с Looper
class WorkerThread : Thread() {
lateinit var handler: Handler
override fun run() {
// Создаем Looper для этого потока
Looper.prepare()
// Создаем Handler, связанный с Looper текущего потока
handler = Handler(Looper.myLooper()!!) { msg ->
// Обработка полученных сообщений
when (msg.what) {
1 -> {
val data = msg.obj as String
println("Получено в рабочем потоке: $data")
}
}
true
}
// Запускаем бесконечный цикл обработки сообщений
Looper.loop()
}
}
Основные способы передачи сообщений
1. Отправка простого сообщения
// Создаем и запускаем рабочий поток
val workerThread = WorkerThread()
workerThread.start()
// Ждем инициализации Handler
Thread.sleep(100) // В реальном коде используйте более надежные методы синхронизации
// Отправляем сообщение из главного потока в рабочий
val message = Message.obtain().apply {
what = 1
obj = "Привет из главного потока!"
}
workerThread.handler.sendMessage(message)
2. Использование Handler для отправки Runnable
// В рабочем потоке создаем Handler
val workerHandler = Handler(workerThread.looper)
// Отправляем Runnable из главного потока
workerHandler.post {
// Этот код выполнится в рабочем потоке
println("Выполняюсь в рабочем потоке: ${Thread.currentThread().name}")
// Можно отправить ответ обратно в главный поток
mainHandler.post {
// Код выполнится в главном потоке
println("Ответ в главном потоке")
}
}
3. Работа с главным потоком (UI Thread)
// Получаем Handler главного потока
val mainHandler = Handler(Looper.getMainLooper())
// Отправляем сообщение в главный поток из фонового
Thread {
// Выполняем тяжелую работу
val result = performHeavyCalculation()
// Обновляем UI через главный поток
mainHandler.post {
textView.text = "Результат: $result"
}
}.start()
Продвинутые методы отправки сообщений
Отправка с задержкой
// Отправить сообщение с задержкой 1 секунда
handler.sendMessageDelayed(message, 1000)
// Отправить Runnable с задержкой
handler.postDelayed({
println("Выполнено с задержкой")
}, 2000)
Отправка в определенное время
val futureTime = SystemClock.uptimeMillis() + 5000
handler.sendMessageAtTime(message, futureTime)
Создание кастомных Handler
class CustomHandler(
looper: Looper,
private val callback: (String) -> Unit
) : Handler(looper) {
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_TYPE_TEXT -> {
val text = msg.obj as? String
text?.let { callback(it) }
}
MSG_TYPE_DATA -> {
val bundle = msg.data
val value = bundle.getString("key")
// Обработка данных
}
}
}
companion object {
const val MSG_TYPE_TEXT = 1
const val MSG_TYPE_DATA = 2
}
}
Полный пример взаимодействия потоков
class ThreadCommunicationExample {
private lateinit var workerThread: WorkerThread
private val mainHandler = Handler(Looper.getMainLooper())
fun startCommunication() {
// Создаем и запускаем рабочий поток
workerThread = WorkerThread().apply {
start()
}
// Даем время на инициализацию Looper
Handler(Looper.getMainLooper()).postDelayed({
sendMessageToWorker()
}, 100)
}
private fun sendMessageToWorker() {
// Создаем сообщение с данными
val message = workerThread.handler.obtainMessage().apply {
what = WorkerThread.MSG_CALCULATE
obj = CalculationData(5, 10)
}
// Отправляем сообщение в рабочий поток
workerThread.handler.sendMessage(message)
}
inner class WorkerThread : Thread() {
lateinit var handler: Handler
companion object {
const val MSG_CALCULATE = 1
const val MSG_RESULT = 2
}
override fun run() {
Looper.prepare()
handler = Handler(Looper.myLooper()!!) { msg ->
when (msg.what) {
MSG_CALCULATE -> {
val data = msg.obj as CalculationData
val result = data.a + data.b
// Отправляем результат в главный поток
val resultMsg = Message.obtain().apply {
what = MSG_RESULT
obj = result
}
mainHandler.sendMessage(resultMsg)
}
}
true
}
Looper.loop()
}
}
data class CalculationData(val a: Int, val b: Int)
}
Важные особенности и лучшие практики
1. Безопасное завершение работы
fun cleanup() {
// Для завершения потока с Looper
workerThread.handler.looper.quitSafely()
}
2. Предотвращение утечек памяти
// Используйте слабые ссылки для контекста
class SafeHandler(
context: Context,
looper: Looper
) : Handler(looper) {
private val weakContext = WeakReference(context)
override fun handleMessage(msg: Message) {
val context = weakContext.get()
context?.let {
// Работа с контекстом
}
}
}
3. Использование HandlerThread
// Встроенный класс для удобной работы
val handlerThread = HandlerThread("WorkerThread")
handlerThread.start()
val handler = Handler(handlerThread.looper)
Заключение
Handler и Looper предоставляют надежный механизм для передачи сообщений между потоками в Android. Ключевые моменты:
- Каждый поток с Looper имеет свою очередь сообщений
- Handler всегда привязан к определенному Looper (и потоку)
- Сообщения обрабатываются последовательно в порядке очереди
- Система гарантирует потокобезопасность при работе с очередью сообщений
- Все операции с UI должны выполняться в главном потоке через
Looper.getMainLooper()
Этот механизм является фундаментальным для работы Android и используется во многих системных компонентах, включая AsyncTask, HandlerThread и IntentService. Понимание его работы критически важно для разработки эффективных и отзывчивых Android-приложений.