Как построить сетевое взаимодействие с помощью Retrofit
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Построение сетевого взаимодействия с помощью Retrofit
Retrofit — это типобезопасный HTTP-клиент для Android и Java, разработанный Square, который упрощает выполнение сетевых запросов за счет преобразования REST API в Java/Kotlin интерфейсы. Он использует OkHttp как транспортный слой и поддерживает различные конвертеры (Gson, Moshi, Jackson) для сериализации данных. Основные преимущества: минималистичный синтаксис, поддержка корутин и RxJava, встроенная обработка ошибок.
Основные шаги реализации
1. Добавление зависимостей
В build.gradle (app) добавляем необходимые библиотеки:
dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
}
2. Определение модели данных Создаем data-классы, соответствующие структуре JSON-ответа:
data class User(
val id: Int,
val name: String,
val email: String,
@SerializedName("avatar_url") val avatarUrl: String?
)
data class ApiResponse<T>(
val data: T,
val status: String,
val message: String?
)
3. Создание API интерфейса Определяем endpoints с аннотациями:
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") userId: Int): ApiResponse<User>
@GET("users")
suspend fun getUsers(@Query("page") page: Int): ApiResponse<List<User>>
@POST("users/create")
@Headers("Content-Type: application/json")
suspend fun createUser(@Body user: User): ApiResponse<User>
@Multipart
@POST("upload")
suspend fun uploadFile(@Part file: MultipartBody.Part): ApiResponse<String>
}
4. Конфигурация Retrofit клиента Создаем объект с настройками:
object RetrofitClient {
private const val BASE_URL = "https://api.example.com/v1/"
private val okHttpClient = OkHttpClient.Builder()
.addInterceptor(LoggingInterceptor())
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService: ApiService by lazy {
retrofit.create(ApiService::class.java)
}
}
5. Реализация Logging Interceptor Для отладки сетевых запросов:
class LoggingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val t1 = System.nanoTime()
// Логирование запроса
Log.d("Retrofit", "Request: ${request.method} ${request.url}")
val response = chain.proceed(request)
val t2 = System.nanoTime()
// Логирование ответа
Log.d("Retrofit", """
Response: ${response.code}
Time: ${(t2 - t1) / 1e6}ms
Headers: ${response.headers}
""".trimIndent())
return response
}
}
6. Выполнение запроса с корутинами Использование в ViewModel или Repository:
class UserRepository {
private val apiService = RetrofitClient.apiService
suspend fun fetchUser(userId: Int): Result<User> {
return try {
val response = apiService.getUser(userId)
if (response.status == "success") {
Result.success(response.data)
} else {
Result.failure(Exception(response.message ?: "Unknown error"))
}
} catch (e: Exception) {
Result.failure(e)
}
}
suspend fun loadUsers(page: Int): Flow<List<User>> = flow {
val response = apiService.getUsers(page)
if (response.status == "success") {
emit(response.data)
} else {
throw IOException(response.message ?: "Failed to load users")
}
}.catch { e ->
// Обработка ошибок
Log.e("UserRepository", "Network error", e)
emit(emptyList())
}
}
Продвинутые техники
Кастомизация интерсепторов:
- AuthenticationInterceptor для добавления токенов
- RetryInterceptor для повторных попыток
- CacheInterceptor для кэширования
Обработка ошибок:
class NetworkExceptionHandler {
companion object {
fun handleException(e: Throwable): String {
return when (e) {
is SocketTimeoutException -> "Timeout error"
is ConnectException -> "No internet connection"
is HttpException -> when (e.code()) {
401 -> "Unauthorized"
404 -> "Not found"
500 -> "Server error"
else -> "HTTP error: ${e.code()}"
}
else -> "Unknown error: ${e.message}"
}
}
}
}
Конфигурация для разных сред:
enum class Environment {
DEVELOPMENT, PRODUCTION
}
object ApiConfig {
private val currentEnv = Environment.DEVELOPMENT
val baseUrl: String
get() = when (currentEnv) {
Environment.DEVELOPMENT -> "https://dev.api.example.com/"
Environment.PRODUCTION -> "https://api.example.com/"
}
}
Best Practices
- Инкапсуляция сетевой логики в Repository слое
- Использование Dependency Injection (Dagger/Hilt) для управления зависимостями
- Тестирование с помощью MockWebServer
- Кэширование ответов для оффлайн-работы
- Пагинация для больших списков данных
- Троттлинг запросов при быстром скроллинге
- Безопасное хранение чувствительных данных (токены, ключи)
Retrofit значительно снижает код-бойлерплейт при работе с сетевыми запросами, обеспечивая при этом гибкость конфигурации и высокую производительность. Ключевой момент — правильная архитектура с разделением ответственности между слоями приложения и грамотной обработкой всех возможных сетевых сценариев.