Retrofit в Android Studio: урок на Kotlin

Сетевые запросы — обязательная часть почти каждого приложения, и Retrofit остаётся самым популярным инструментом для их выполнения. В этом уроке из цикла Android Studio: уроки на Kotlin мы с нуля подключим Retrofit, напишем API-интерфейс, получим данные с сервера и отобразим их на экране. Материал рассчитан на тех, кто впервые берётся за работу с сетью, поэтому каждый шаг разбирается подробно.


Что такое Retrofit и почему именно он

Retrofit — это библиотека от Square, которая превращает описание HTTP-запроса в обычный Kotlin-интерфейс. Вы просто помечаете метод аннотацией вроде @GET, указываете параметры — а Retrofit сам строит запрос, выполняет его и превращает ответ в готовый объект. По сравнению с ручной работой через HttpURLConnection код сокращается в несколько раз, а читаемость вырастает на порядок.


Стартовый набор зависимостей

Для начала откройте build.gradle.kts на уровне модуля и добавьте три строки. Первая — сам Retrofit, вторая — конвертер для превращения JSON в объекты, третья — библиотека корутин для асинхронной работы.

dependencies {
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
}

Конвертер Gson — самый популярный, но при желании вы можете заменить его на Moshi или Jackson, логика останется той же. После синхронизации Gradle можно начинать писать код.


Создаём модель данных

Прежде чем слать запросы, нужно описать, как выглядит объект, который придёт с сервера. Создайте data-класс, поля которого совпадают с ключами в JSON-ответе. Для примера возьмём публичное API — список постов.

data class Post(
    val userId: Int,
    val id: Int,
    val title: String,
    val body: String
)

Gson автоматически сопоставит названия полей с ключами JSON. Если ключи называются иначе, используйте аннотацию @SerializedName.


Описываем API-интерфейс

Теперь самое интересное — интерфейс, который описывает, какие запросы умеет отправлять приложение. Каждый метод соответствует одному эндпоинту. Аннотация @GET задаёт путь, а возвращаемый тип оборачивается в Call или, в нашем случае, в suspend-функцию.

interface ApiService {
    @GET("posts")
    suspend fun getPosts(): List<Post>
}

Обратите внимание на suspend: благодаря этому мы сможем вызывать метод внутри корутины и не думать о колбэках. Retrofit начиная с версии 2.6.0 полностью поддерживает корутины.


Конфигурируем экземпляр Retrofit

Интерфейс сам себя не использует — нужен билдер, который задаст базовый URL, подключит конвертер и создаст реализацию. Обычно это делают в companion object или через DI, но для урока хватит простого создания.

val retrofit = Retrofit.Builder()
    .baseUrl("https://jsonplaceholder.typicode.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

val apiService = retrofit.create(ApiService::class.java)

Базовый URL обязан заканчиваться слешем. Если путь в аннотации начинается с /, то он переопределит базовый URL, поэтому будьте внимательны.


Пишем запрос и обрабатываем ответ

Для сетевых операций нужна корутина, запущенная в скоупе ViewModel или Activity. Внутри неё вызываем suspend-функцию и оборачиваем в try-catch — сеть непредсказуема, ошибки должны обрабатываться.

lifecycleScope.launch {
    try {
        val posts = apiService.getPosts()
        // обновляем UI полученным списком
    } catch (e: Exception) {
        // показываем сообщение об ошибке
    }
}

Если ответ успешен, в переменной posts уже будет готовый список объектов Post. Если сервер вернул ошибку, Retrofit выбросит HttpException, которую можно поймать и отдельно обработать.


Отображаем данные в Compose

Вся сила подхода Android Studio: уроки на Kotlin — в связке современных инструментов. Полученный список передадим в состояние и выведем в LazyColumn. Пример Compose-экрана:

@Composable
fun PostList(posts: List<Post>) {
    LazyColumn {
        items(posts) { post ->
            Card(modifier = Modifier.fillMaxWidth().padding(8.dp)) {
                Column(modifier = Modifier.padding(16.dp)) {
                    Text(post.title, style = MaterialTheme.typography.titleMedium)
                    Spacer(modifier = Modifier.height(4.dp))
                    Text(post.body, style = MaterialTheme.typography.bodyMedium)
                }
            }
        }
    }
}

Это минимальный пример. В реальном проекте вы обернёте экран во ViewModel, добавите индикатор загрузки и обработку ошибок, но суть останется такой же.


Частые ошибки и как их избежать

  • Забытый INTERNET permission. Без <uses-permission android:name="android.permission.INTERNET"/> в манифесте приложение не выполнит ни одного запроса.
  • Блокировка главного потока. Никогда не вызывайте execute() вместо enqueue или suspend-функции в UI-потоке — это приведёт к крашу.
  • Расхождение имён полей. Если ответ сервера содержит поле user_id, а модель ожидает userId, Gson проигнорирует его. Используйте @SerializedName("user_id").
  • Неправильный baseUrl. Проверьте, что базовый URL заканчивается на /, а путь в @GET — нет. Исключение: если путь начинается с /, он будет абсолютным и заменит базовый URL.

Сводка методов Retrofit


Аннотация Назначение Пример
@GET("путь") GET-запрос для получения данных suspend fun getPosts(): List<Post>
@POST("путь") POST-запрос для создания ресурса suspend fun createPost(@Body post: Post): Post
@PUT("путь/{id}") PUT-запрос для полного обновления suspend fun updatePost(@Path("id") id: Int, @Body post: Post): Post
@DELETE("путь/{id}") DELETE-запрос для удаления suspend fun deletePost(@Path("id") id: Int)
@Query("имя") Добавление параметра в URL suspend fun search(@Query("q") query: String): List<Post>

Что мы освоили

Сегодняшний урок из цикла Android Studio: уроки на Kotlin научил вас интегрировать Retrofit, описывать модель, создавать API-интерфейс и выполнять асинхронные запросы. Вы получили готовый каркас, который можно сразу перенести в свой проект и расширить дополнительными эндпоинтами, аутентификацией, интерцепторами. Retrofit — это незаменимый инструмент современного Android-разработчика, и теперь он у вас в арсенале.