Как выполнить HTTP-запрос в Android на Kotlin (Retrofit, OkHttp, Ktor)
Полный гайд: 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 — он уменьшает шаблонный код.