Что такое Retrofit и зачем он нужен?
Retrofit — это типобезопасный HTTP-клиент для Java и Kotlin, разработанный компанией Square. Это одна из самых популярных библиотек для работы с REST API в экосистеме Android. Retrofit позволяет разработчикам легко и элегантно выполнять HTTP-запросы к удаленным серверам, автоматически преобразуя JSON-ответы в Kotlin-объекты и наоборот.
Зачем нужен Retrofit?
- Упрощение работы с API: Вместо написания громоздкого кода с HttpURLConnection или OkHttp, вы определяете интерфейс с аннотациями, и Retrofit сам генерирует реализацию.
- Автоматическая сериализация/десериализация: Благодаря интеграции с конвертерами (Gson, Moshi, Kotlinx Serialization), Retrofit автоматически преобразует JSON в Kotlin-объекты.
- Поддержка различных HTTP-методов: GET, POST, PUT, DELETE, PATCH, HEAD и OPTIONS.
- Управление заголовками и параметрами: Легко добавлять динамические или статические заголовки, query-параметры и path-параметры.
- Асинхронность: Поддержка корутин Kotlin (suspend функции) и Callback-интерфейсов.
- Интеграция с OkHttp: Retrofit использует OkHttp как HTTP-движок, что дает доступ к мощным возможностям перехвата запросов (interceptors).
Retrofit идеально подходит для Android-приложений, которые взаимодействуют с RESTful веб-сервисами: от простых погодных приложений до сложных социальных сетей.
Установка Retrofit в проект Kotlin
В отличие от Python (где используется pip), в Kotlin/Android проектах зависимости управляются через Gradle. Добавьте следующие строки в файл build.gradle.kts (или build.gradle) вашего модуля (обычно app):
// build.gradle.kts (Module :app)
dependencies {
// Основная библиотека Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// Конвертер для работы с JSON (Gson)
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// Альтернативный конвертер (Moshi)
// implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
// Для поддержки корутин (suspend функции)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
// OkHttp (обычно уже включен, но можно добавить явно)
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
}
Важно: После добавления зависимостей нажмите "Sync Now" в Android Studio, чтобы загрузить библиотеки.
Быстрый старт: пример кода
Давайте создадим простое приложение, которое получает список постов с JSONPlaceholder (бесплатный тестовый API).
Шаг 1: Создайте data-класс для ответа
data class Post(
val userId: Int,
val id: Int,
val title: String,
val body: String
)
Шаг 2: Определите API-интерфейс
interface ApiService {
@GET("posts")
suspend fun getPosts(): List<Post>
@GET("posts/{id}")
suspend fun getPostById(@Path("id") postId: Int): Post
}
Шаг 3: Создайте Retrofit-клиент
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)
}
}
Шаг 4: Используйте в Activity или ViewModel
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Запускаем корутину
CoroutineScope(Dispatchers.IO).launch {
try {
val posts = RetrofitClient.instance.getPosts()
withContext(Dispatchers.Main) {
// Обновляем UI
println("Получено ${posts.size} постов")
}
} catch (e: Exception) {
println("Ошибка: ${e.message}")
}
}
}
}
Основные методы и функции Retrofit
1. @GET — GET-запрос
Описание: Выполняет HTTP GET-запрос для получения данных с сервера.
Параметры: URL-путь (строка), может содержать path-параметры.
@GET("users")
suspend fun getUsers(): List<User>
@GET("users/{id}")
suspend fun getUserById(@Path("id") userId: Int): User
2. @POST — POST-запрос
Описание: Отправляет данные на сервер для создания нового ресурса.
Параметры: URL-путь, тело запроса (@Body).
@POST("posts")
suspend fun createPost(@Body post: Post): Post
3. @PUT — PUT-запрос
Описание: Обновляет существующий ресурс на сервере (полная замена).
Параметры: URL-путь с id, тело запроса.
@PUT("posts/{id}")
suspend fun updatePost(@Path("id") postId: Int, @Body post: Post): Post
4. @DELETE — DELETE-запрос
Описание: Удаляет ресурс на сервере.
Параметры: URL-путь с id.
@DELETE("posts/{id}")
suspend fun deletePost(@Path("id") postId: Int): Response<Unit>
5. @PATCH — PATCH-запрос
Описание: Частичное обновление ресурса (в отличие от PUT, который заменяет весь объект).
Параметры: URL-путь с id, тело запроса с частичными данными.
@PATCH("posts/{id}")
suspend fun patchPost(@Path("id") postId: Int, @Body updates: Map<String, Any>): Post
6. @Query — Query-параметры
Описание: Добавляет параметры запроса в URL (например, ?userId=1).
Параметры: Имя параметра, значение.
@GET("posts")
suspend fun getPostsByUser(@Query("userId") userId: Int): List<Post>
// Множественные параметры
@GET("posts")
suspend fun getFilteredPosts(
@Query("userId") userId: Int,
@Query("_sort") sort: String = "id",
@Query("_order") order: String = "desc"
): List<Post>
7. @Path — Path-параметры
Описание: Заменяет динамические части URL-пути.
Параметры: Имя параметра (должно совпадать с именем в фигурных скобках в URL).
@GET("users/{userId}/posts/{postId}")
suspend fun getUserPost(
@Path("userId") userId: Int,
@Path("postId") postId: Int
): Post
8. @Header и @Headers — Заголовки
Описание: Добавляет HTTP-заголовки к запросу. @Header — динамический заголовок, @Headers — статические.
Параметры: Имя и значение заголовка.
// Динамический заголовок
@GET("protected/posts")
suspend fun getProtectedPosts(@Header("Authorization") token: String): List<Post>
// Статические заголовки
@Headers("Cache-Control: max-age=3600", "Accept: application/json")
@GET("posts")
suspend fun getCachedPosts(): List<Post>
9. @Body — Тело запроса
Описание: Передает объект в теле запроса. Автоматически сериализуется в JSON (или другой формат).
Параметры: Любой Kotlin-объект.
data class LoginRequest(val username: String, val password: String)
@POST("auth/login")
suspend fun login(@Body credentials: LoginRequest): Response<LoginResponse>
10. @FormUrlEncoded и @Field — Форма
Описание: Отправляет данные в формате application/x-www-form-urlencoded (как HTML-форма).
Параметры: Пары ключ-значение.
@FormUrlEncoded
@POST("auth/login")
suspend fun loginForm(
@Field("username") username: String,
@Field("password") password: String
): Response<LoginResponse>
11. @Multipart и @Part — Многокомпонентные запросы
Описание: Отправляет файлы и данные в формате multipart/form-data (для загрузки файлов).
Параметры: @Part для каждого поля/файла.
@Multipart
@POST("upload")
suspend fun uploadFile(
@Part("description") description: RequestBody,
@Part file: MultipartBody.Part
): Response<UploadResponse>
12. @Streaming — Потоковая передача
Описание: Позволяет работать с ResponseBody как с потоком, не загружая его полностью в память. Полезно для больших файлов.
Параметры: Нет.
@Streaming
@GET("large-file.zip")
suspend fun downloadLargeFile(): ResponseBody
Реальный практический пример использования
Давайте создадим полноценный пример: приложение для просмотра погоды с использованием OpenWeatherMap API.
1. Data-классы
data class WeatherResponse(
val main: Main,
val weather: List<Weather>,
val name: String
)
data class Main(
val temp: Double,
val feels_like: Double,
val humidity: Int
)
data class Weather(
val description: String,
val icon: String
)
2. API-интерфейс
interface WeatherApiService {
@GET("weather")
suspend fun getCurrentWeather(
@Query("q") cityName: String,
@Query("appid") apiKey: String,
@Query("units") units: String = "metric"
): WeatherResponse
}
3. Retrofit-клиент с логированием
object WeatherClient {
private const val BASE_URL = "https://api.openweathermap.org/data/2.5/"
val instance: WeatherApiService by lazy {
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(WeatherApiService::class.java)
}
}
4. ViewModel для управления состоянием
class WeatherViewModel : ViewModel() {
private val _weatherState = MutableStateFlow<WeatherUiState>(WeatherUiState.Loading)
val weatherState: StateFlow<WeatherUiState> = _weatherState.asStateFlow()
fun fetchWeather(city: String) {
viewModelScope.launch {
_weatherState.value = WeatherUiState.Loading
try {
val response = WeatherClient.instance.getCurrentWeather(
cityName = city Также в библиотеке
Авторизация и аутентификация в Java: полное руководство
Конфигурация приложений на C++: библиотеки и инструменты для гибкой настройки
bcrypt для Go: полное руководство с примерами
ORM для Rust: сравнение и примеры Diesel, SeaORM, SQLx