1. 添加依赖
确保在 build.gradle
文件中添加了必要的依赖:
dependencies {
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
// Kotlin Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
// Lifecycle (用于协程的 lifecycleScope)
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
}
2. 定义数据模型
定义数据模型类,例如 User
:
data class User(
val id: Int,
val name: String,
val email: String
)
3. 定义 API 接口
使用 Retrofit 的注解定义 API 接口:
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") userId: Int): Response<User>
@GET("users")
suspend fun getUsers(): Response<List<User>>
@POST("refresh_token")
suspend fun refreshToken(): Response<TokenResponse>
}
4. 创建 Retrofit 实例
创建 Retrofit 实例并配置它,包括日志拦截器、失败重试拦截器和 Token 刷新拦截器:
object RetrofitClient {
private const val BASE_URL = "https://api.example.com/"
private const val MAX_RETRIES = 3
val apiService: ApiService by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient())
.build()
.create(ApiService::class.java)
}
private fun okHttpClient(): OkHttpClient {
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
val retryInterceptor = RetryInterceptor(MAX_RETRIES)
val tokenRefreshInterceptor = TokenRefreshInterceptor()
return OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(retryInterceptor)
.addInterceptor(tokenRefreshInterceptor)
.build()
}
}
5. 实现拦截器
5.1 日志拦截器
日志拦截器已经通过 HttpLoggingInterceptor
实现。
5.2 失败重试拦截器
实现一个失败重试拦截器:
class RetryInterceptor(private val maxRetries: Int) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var retries = 0
var request = chain.request()
var response: Response? = null
while (retries < maxRetries) {
try {
response = chain.proceed(request)
if (response.isSuccessful) {
return response
}
} catch (e: IOException) {
// Log the exception
}
retries++
}
return response ?: throw IOException("Failed to retry request")
}
}
5.3 Token 刷新拦截器
实现一个 Token 刷新拦截器:
class TokenRefreshInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val response = chain.proceed(request)
if (response.code == 401) { // Token 失效
val refreshTokenResponse = RetrofitClient.apiService.refreshToken()
if (refreshTokenResponse.isSuccessful) {
val newToken = refreshTokenResponse.body()?.token
if (newToken != null) {
// 更新 Token
// 重新发送请求
val newRequest = request.newBuilder()
.header("Authorization", "Bearer $newToken")
.build()
return chain.proceed(newRequest)
}
}
}
return response
}
}
6. 封装网络请求
封装网络请求逻辑,使用协程和 Flow:
import kotlinx.coroutines.flow.flow
import retrofit2.Response
object NetworkRepository {
suspend fun fetchUser(userId: Int) = RetrofitClient.apiService.getUser(userId)
suspend fun fetchUsers() = RetrofitClient.apiService.getUsers()
}
7. 在 ViewModel 中使用封装的网络请求
在 ViewModel 中调用封装的网络请求,并使用 StateFlow
或 LiveData
管理状态:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*
class MainViewModel : ViewModel() {
private val _networkState = MutableStateFlow<NetworkState<List<User>>>(NetworkState.Loading())
val networkState = _networkState.asLiveData()
init {
fetchUsers()
}
private fun fetchUsers() {
viewModelScope.launch {
_networkState.value = NetworkState.Loading()
try {
val response = NetworkRepository.fetchUsers()
if (response.isSuccessful) {
_networkState.value = NetworkState.Success(response.body()!!)
} else {
_networkState.value = NetworkState.Error(Exception("Error: ${response.code()}"))
}
} catch (e: Exception) {
_networkState.value = NetworkState.Error(e)
}
}
}
}
8. 在 Activity 或 Fragment 中观察数据
在 Activity 或 Fragment 中观察 ViewModel 中的数据,并更新 UI:
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.networkState.observe(this) { state ->
when (state) {
is NetworkState.Loading -> {
// Show loading
}
is NetworkState.Success -> {
// Update UI with users
}
is NetworkState.Error -> {
// Show error
}
}
}
}
}
9. 错误处理和加载状态管理
可以进一步封装错误处理和加载状态管理,例如使用密封类来表示网络请求的状态:
sealed class NetworkState<out T : Any> {
class Loading<out T : Any> : NetworkState<T>()
data class Success<out T : Any>(val data: T) : NetworkState<T>()
data class Error<out T : Any>(val exception: Exception) : NetworkState<T>()
}
通过以上步骤,你可以实现一个高效、简洁且易于维护的 Retrofit 风格的网络请求封装,结合协程和 Flow,使得网络请求的代码更加优雅。