Работал ли с потоками

Ответ

Да, работал. В Android есть несколько способов работы с потоками:

  1. Thread - базовый класс Java для создания потоков:
new Thread(() -> {
    // Фоновый код
    runOnUiThread(() -> {
        // Обновление UI
    });
}).start();
  1. Handler/Looper - для работы с очередью сообщений:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {
    // Код выполнится в основном потоке
});
  1. AsyncTask (устарел) - для простых фоновых задач с обновлением UI.

  2. Coroutines - современный подход:

lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        // Фоновый код
    }
    // Обновление UI (автоматически в основном потоке)
}
  1. RxJava - реактивное программирование.

Важно помнить:

  • UI можно обновлять только в основном потоке
  • Долгие операции нельзя выполнять в основном потоке
  • Для работы с сетью/БД/файлами нужно использовать фоновые потоки

Ответ 18+ 🔞

О, слушай, тут один чувак на собеседовании такой вопрос задал, я чуть со стула не упал. Спрашивает: «А как в Андроиде с потоками работать?». Ну, ёпта, вопрос-то вроде базовый, но если ты с ним на «ты», то уже полдела сделано. Давай разберём, как не накосячить и не получить ANR, от которого у пользователя волосы дыбом встанут.

Первый способ, дедовский, как папины джинсы — Thread.
Просто взял и создал. Но тут главное — не обосраться с обновлением интерфейса. UI-поток — он один, и лезть к нему из другого потока — это как в чужую тарелку совать ложку: получишь по рукам (в виде краха приложения).

Thread {
    // Тут делаешь всю тяжёлую работу: сетевой запрос, парсинг JSON, который весит овердохуища.
    // Потом, когда надо UI обновить:
    runOnUiThread {
        // А вот тут уже безопасно тыкаешь в TextView и ProgressBar
    }
}.start()

Работает? Работает. Удобно? Ну, как посмотреть. Для разовой задачи сойдёт, но если таких потоков накрутить десяток, управлять ими — тот ещё геморрой. Подозрение ебать чувствую, что где-то что-то не заджойнится и будет висеть.

Второй вариант — Handler с Looper'ом.
Это уже посерьёзнее, система очередей сообщений. Кидаешь задачу в очередь главного потока — и она выполнится, когда до неё дойдёт черёд.

val handler = Handler(Looper.getMainLooper())
handler.post {
    // Всё, что здесь написано, выполнится в UI-потоке. Безопасно, чётко.
}

Штука мощная, но если начать через него гонять тонны мелких задач, можно так заспамить очередь, что интерфейс начнёт дёргаться, как будто его током бьёт. Терпения ноль ебать у пользователя будет.

Третий — AsyncTask. Про него можно смело забыть, он накрылся медным тазом.
Да, раньше все его юзали, он был как родной. Но сейчас он deprecated, и правильно — архитектура у него была так себе, писали на нём обычно кривовато, и он частенько протекал, как решето. Доверия ебать ноль к нему.

Четвёртый, современный и модный — корутины (Kotlin Coroutines).
Вот это, бля, действительно удобно. Выглядит как последовательный код, а работает асинхронно. Магия, да и только.

lifecycleScope.launch {
    // Всё, что здесь — уже не в UI-потоке? А вот и нет! По умолчанию — главный поток.
    // Поэтому для тяжёлой работы переключаемся:
    val result = withContext(Dispatchers.IO) {
        // А вот тут уже точно фоновый поток. Делаем что надо.
        return@withContext heavyCalculation()
    }
    // А после withContext мы автоматом возвращаемся в главный поток! Красота.
    // Можешь спокойно обновлять UI.
}

Это сейчас основной способ. Управление отменой задач, удобные скоупы (типа viewModelScope), минимум boilerplate кода. Рекомендую к изучению, если ещё не в теме.

Пятый — RxJava.
Мощнейшая библиотека, целая философия реактивного программирования. Но, чувак, это как управлять космическим кораблём, чтобы до магазина за хлебом сходить. Кривая обучения — пиздец какая крутая. Если в проекте её нет, а ты её притащишь только для запроса к API — это чих-пых тебя в сраку. Overkill полный. Но если уж весь проект на ней живёт, то деваться некуда — учи.

Главные правила, которые надо выжечь в мозгу кислотой:

  1. UI обновляется ТОЛЬКО в главном (UI) потоке. Полез из фонового потока что-то ткнуть в TextView — получишь CalledFromWrongThreadException. Приложение ебанько сделает и упадёт.
  2. Никаких долгих операций в главном потоке! Сеть, база данных, чтение большого файла, сложные вычисления — всё это делай в фоне. Иначе интерфейс замрёт, пользователь увидит «Application Not Responding» и пошлёт тебя и твоё приложение на хуй.
  3. Выбирай инструмент по задаче. Не тащи корутины или RxJava в учебный проект из трёх экранов. Но и не лепи десять Thread'ов в продакшн-приложение.

Короче, суть в том, чтобы разделять: фон — для работы, UI-поток — для отображения результата. Соблюдаешь это — и жить будет проще, и приложение не будет лагать, как старая маршрутка.