Что такое main thread? Какие операции нужно выполнять на main thread, а какие нельзя делать?android-34

Что такое Main Thread?

Main Thread (главный поток, UI-поток) — это основной поток выполнения в Android-приложении, который:

  1. Создается автоматически при запуске приложения
  2. Отвечает за обработку всех пользовательских событий (тапы, скроллы и т.д.)
  3. Управляет обновлением UI-компонентов
  4. Вызывает жизненные циклы Activity/Fragment
// Проверка, выполняется ли код в main thread
if (Looper.myLooper() == Looper.getMainLooper()) {
    // Это главный поток
}

Операции, которые должны выполняться на Main Thread

  1. Все операции с UI:
    • Изменение свойств View (текст, видимость, позиция)
    • Обработка пользовательского ввода
    • Вызов методов View (invalidate(), requestLayout())
textView.text = "Обновленный текст"
button.isEnabled = false
recyclerView.smoothScrollToPosition(0)
  1. Работа с жизненными циклами:

    • onCreate(), onStart(), onResume() и другие callback-и
    • Обработка результата startActivityForResult()
  2. Вызовы методов, требующие Main Thread:

    • Toast.makeText().show()
    • Snackbar.show()
    • Диалоги (AlertDialog, DatePickerDialog)

Операции, которые нельзя выполнять на Main Thread

  1. Долгие операции (более 5-16 мс):

    • Сетевые запросы (HTTP, WebSocket)
    • Работа с базой данных (Room, SQLite)
    • Чтение/запись файлов
  2. Блокирующие операции:

    • Thread.sleep()
    • Синхронные вызовы (без колбэков)
    • Ожидание других потоков (wait(), join())
  3. Сложные вычисления:

    • Обработка изображений/видео
    • Парсинг больших JSON/XML
    • Машинное обучение (инференс моделей)

Что происходит при нарушении?

  • ANR (Application Not Responding) — если главный поток блокируется более 5 секунд
  • Подергивания интерфейса — при задержках более 16 мс (60 FPS)
  • Краши приложения — например, NetworkOnMainThreadException

Как перенести работу с Main Thread?

  1. Kotlin Coroutines:
lifecycleScope.launch {
    val data = withContext(Dispatchers.IO) { // фоновый поток
        repository.loadData() // долгая операция
    }
    textView.text = data // автоматически возвращается в main thread
}
  1. RxJava:
Observable.fromCallable { /* долгая операция */ }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe { result -> updateUI(result) }
  1. AsyncTask (устарел):
private class MyTask extends AsyncTask<Void, Void, String> {
    protected String doInBackground(Void... voids) {
        return "Результат"; // в фоне
    }
    protected void onPostExecute(String result) {
        textView.setText(result); // в UI потоке
    }
}

Исключения и особые случаи

  1. Room автоматически переносит запросы в фоновый поток при использовании Flow/LiveData
  2. View.post() позволяет безопасно обновлять UI из любого потока:
view.post(() -> {
    // Этот код выполнится в main thread
    view.setVisibility(View.VISIBLE);
});

Резюмируем:

Main Thread — критически важный поток в Android, отвечающий за UI и взаимодействие с пользователем. Долгие и блокирующие операции должны выполняться в фоновых потоках, а результаты передаваться обратно для обновления интерфейса. Соблюдение этого правила — основа плавного и отзывчивого интерфейса.