Avatar ·

Как выполнить HTTP-запрос в Android на Kotlin (Retrofit, OkHttp, Ktor)

Всем привет! Я только начал изучать Kotlin для Android и столкнулся с проблемой выполнения HTTP-запросов. Мне нужно получить данные с REST API (например, список пользователей) и отобразить их в RecyclerView. Пробовал использовать старый AsyncTask, но везде пишут, что он устарел и его нельзя использовать в новых версиях Android. Вот пример моего кода, который не работает: ```kotlin class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val url = "https://jsonplaceholder.typicode.com/users" val result = URL(url).readText() // Выдаёт NetworkOnMainThreadException textView.text = result } } ``` Я понимаю, что нельзя делать сетевые запросы в главном потоке. Но как правильно организовать асинхронный запрос? Нужно ли добавлять какие-то зависимости в Gradle? Что использовать: OkHttp, Retrofit, Ktor или что-то ещё? Как обрабатывать ошибки сети и парсить JSON? Буду благодарен за подробный пример с объяснением, желательно с использованием современного подхода (Coroutines + Retrofit). Также интересует: нужно ли добавлять разрешение INTERNET в манифест? Как тестировать запросы на эмуляторе? Заранее спасибо за помощь! <<>>

Полный гайд: HTTP-запросы в Android на Kotlin (Retrofit + Coroutines)

Вы правы: AsyncTask устарел, а выполнение запросов в главном потоке вызывает NetworkOnMainThreadException. Современный подход — использовать Retrofit в связке с Kotlin Coroutines. Это даёт чистый, безопасный и легко читаемый код.

1. Добавьте разрешение в манифест

В файле AndroidManifest.xml перед тегом <application> добавьте:

<uses-permission android:name="android.permission.INTERNET" />

Для Android 9+ (API 28) также нужно разрешить HTTP (не HTTPS) трафик, если API использует HTTP:

android:usesCleartextTraffic="true"

2. Подключите зависимости в build.gradle (Module)

dependencies {
    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    
    // Coroutines
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
    
    // Lifecycle (для viewModelScope)
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
}

3. Создайте модель данных (data class)

data class User(
    val id: Int,
    val name: String,
    val email: String,
    val phone: String
)

4. Создайте интерфейс API

interface ApiService {
    @GET("users")
    suspend fun getUsers(): List<User>
}

5. Создайте Retrofit клиент (singleton)

object RetrofitClient {
    private const val BASE_URL = "https://jsonplaceholder.typicode.com/"
    
    val instance: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

6. Используйте в Activity/ViewModel

Лучше использовать ViewModel для избежания утечек памяти:

class MainViewModel : ViewModel() {
    private val _users = MutableLiveData<List<User>>()
    val users: LiveData<List<User>> get() = _users
    
    private val _error = MutableLiveData<String>()
    val error: LiveData<String> get() = _error
    
    fun loadUsers() {
        viewModelScope.launch {
            try {
                val response = RetrofitClient.instance.getUsers()
                _users.value = response
            } catch (e: Exception) {
                _error.value = "Ошибка загрузки: ${e.localizedMessage}"
            }
        }
    }
}

В Activity наблюдайте за данными:

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MainViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
        viewModel.loadUsers()
        
        viewModel.users.observe(this) { users ->
            // Обновите RecyclerView или TextView
            textView.text = users.joinToString("\n") { it.name }
        }
        
        viewModel.error.observe(this) { errorMessage ->
            Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show()
        }
    }
}

Важные моменты:

  • Coroutines — suspend функции работают в фоновом потоке, а результат возвращается в главный.
  • viewModelScope автоматически отменяет запросы при уничтожении ViewModel.
  • Для тестирования на эмуляторе используйте 10.0.2.2 вместо localhost.
  • Обрабатывайте исключения сети (No Internet, Timeout) в блоке try-catch.

Этот подход — стандарт индустрии для Android-разработки на Kotlin в 2024 году.

<<>>

Альтернатива: OkHttp + Coroutines (без Retrofit)

Если вам не нужна полноценная библиотека для REST API, можно использовать OkHttp напрямую. Это даёт больше контроля над запросами, но требует ручного парсинга JSON.

Подключите зависимости:

implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
implementation 'com.google.code.gson:gson:2.10.1'

Пример выполнения GET-запроса:

class NetworkHelper {
    private val client = OkHttpClient()
    private val gson = Gson()
    
    suspend fun fetchUsers(): List<User> = withContext(Dispatchers.IO) {
        val request = Request.Builder()
            .url("https://jsonplaceholder.typicode.com/users")
            .build()
        
        val response = client.newCall(request).execute()
        if (!response.isSuccessful) {
            throw IOException("Ошибка: ${response.code}")
        }
        
        val body = response.body?.string() ?: throw IOException("Пустой ответ")
        gson.fromJson(body, Array<User>::class.java).toList()
    }
}

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

fun loadUsers() {
    viewModelScope.launch {
        try {
            val users = NetworkHelper().fetchUsers()
            _users.value = users
        } catch (e: Exception) {
            _error.value = e.localizedMessage
        }
    }
}

OkHttp подходит для простых запросов, загрузки файлов или когда нужно тонко настроить кэширование и таймауты. Для REST API с несколькими эндпоинтами всё же рекомендую Retrofit — он уменьшает шаблонный код.