← Назад к вопросам

Как передать сообщение с одного потока на другой с помощью 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-приложений.

Как передать сообщение с одного потока на другой с помощью Handler и Looper? | PrepBro