Как исправить "android.os.NetworkOnMainThreadException" в Android?

Исключение android.os.NetworkOnMainThreadException возникает, когда приложение пытается выполнить сетевую операцию в основном (UI) потоке в Android. Это ограничение введено для того, чтобы предотвратить блокировку пользовательского интерфейса при выполнении сетевых операций, что может привести к плохой производительности или зависанию приложения.

Как исправить ошибку:

1. Используйте фоновый поток (AsyncTask, Executors или Kotlin Coroutines)

Сетевые операции должны выполняться в фоновом потоке, чтобы избежать блокировки UI.

Использование Kotlin Coroutines (предпочтительный способ для современного Android-разработки):

Корутины Kotlin являются лёгким и удобным способом работы с асинхронным кодом и предпочтительнее использования AsyncTask в современной разработке.

import kotlinx.coroutines.*
import java.net.URL

// Внутри ViewModel или другого класса, где выполняется сетевая операция:
fun fetchData() {
    // Запуск корутины в контексте IO для сетевых запросов
    CoroutineScope(Dispatchers.IO).launch {
        try {
            val result = URL("https://example.com").readText()
            // Переключение на главный поток для обновления UI
            withContext(Dispatchers.Main) {
                // Обновите UI результатом
            }
        } catch (e: Exception) {
            // Обработка исключений
        }
    }
}

Использование AsyncTask (устарело в Android 11):

Если вы работаете с более старыми версиями Android, AsyncTask может использоваться, хотя он уже устарел.

private class NetworkTask : AsyncTask<String, Void, String>() {
    override fun doInBackground(vararg urls: String?): String {
        return try {
            val result = URL(urls[0]).readText()
            result
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }

    override fun onPostExecute(result: String?) {
        // Обновление UI результатом
    }
}

// Запуск задачи:
NetworkTask().execute("https://example.com")

Использование Executors:

Executors позволяют создавать и управлять фоновыми потоками.

val executor = Executors.newSingleThreadExecutor()
val handler = Handler(Looper.getMainLooper())

executor.execute {
    try {
        val result = URL("https://example.com").readText()
        handler.post {
            // Обновление UI в основном потоке
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

2. Используйте WorkManager для фоновых задач:

Для длительных фоновых задач или задач, которые нужно запланировать, рекомендуется использовать WorkManager.

val workRequest = OneTimeWorkRequestBuilder<NetworkWorker>().build()
WorkManager.getInstance(context).enqueue(workRequest)

3. Убедитесь, что код не выполняется в основном потоке:

Убедитесь, что любая сетевая операция обрабатывается в фоновом режиме, будь то через корутины, Executors или WorkManager.

Так вы избежите исключения NetworkOnMainThreadException и улучшите отзывчивость вашего приложения.