Skip to content

网络请求

相关依赖

app/src/main/java/com/joker/kit/core/network 负责 Retrofit + OkHttp 的统一封装,并通过 DataSource/Service 的分层为 core/data 仓库提供网络数据。模块包含以下子目录:

  • base/:抽象基类,提供 Retrofit.createService() 等工具。
  • service/:Retrofit 接口,定义 HTTP 方法与路径。
  • datasource/:网络数据源,组合 Service 并对外提供挂起函数。
  • interceptor/:认证、日志、调试拦截器。
  • di/:Hilt 模块,注入 Retrofit、OkHttp、Service、DataSource。

依赖与 BuildConfig

app/build.gradle.kts 中已经集成 Retrofit、OkHttp、Chucker 等依赖,同时通过 buildConfigField 定义 BASE_URLDEBUG(依赖版本集中在 gradle/libs.versions.toml,每个库都附上官方文档链接,方便查阅/升级):

kotlin
buildTypes {
    debug {
        buildConfigField("String", "BASE_URL", "\"https://box.dusksnow.top/app/\"")
        buildConfigField("Boolean", "DEBUG", "true")
    }
    release {
        buildConfigField("String", "BASE_URL", "\"https://box.dusksnow.top/app/\"")
        buildConfigField("Boolean", "DEBUG", "false")
    }
}

修改请求地址:直接在对应的 buildType 中调整 BASE_URL(或使用不同的 Gradle property)。所有 Retrofit 实例会读取 BuildConfig.BASE_URL

NetworkModule(Retrofit/OkHttp)

NetworkModule 提供 Retrofit 与 OkHttp 实例:

  • OkHttp 拦截器链AuthInterceptor(读取本地 token 并写入 Header)、HttpLoggingInterceptor(根据 BuildConfig.DEBUG 控制日志级别)、调试环境下注入 ChuckerInterceptor 方便抓包。
  • 超时重试:连接/读写超时均为 10 秒,开启 retryOnConnectionFailure(true)
  • 序列化:使用 kotlinx.serialization 转换器,配置了 ignoreUnknownKeys 等参数,避免服务端字段变更导致解析失败。

拦截器

  • AuthInterceptor:调用 AuthStoreDataSource.getToken()(runBlocking)获取 token,若存在则添加到 Authorization Header。
  • LoggingInterceptor:封装 HttpLoggingInterceptor,打印请求/响应日志;release 版本关闭日志。
  • Chucker:在 NetworkModule 的 OkHttp 构建中 if (BuildConfig.DEBUG) 加入 ChuckerInterceptor,可在手机上查看 HTTP 抓包。

真正的调用链:Service → DataSource → Repository

以下以 商品模块 为例说明整个调用链。

1. Service(core/network/service/GoodsService.kt

kotlin
interface GoodsService {
    @POST("goods/info/page")
    suspend fun getGoodsPage(@Body params: GoodsSearchRequest): NetworkResponse<NetworkPageData<Goods>>

    @GET("goods/info/info")
    suspend fun getGoodsInfo(@Query("id") id: String): NetworkResponse<Goods>
}

2. DataSource(core/network/datasource/goods/

  • 接口 GoodsNetworkDataSource.kt
kotlin
interface GoodsNetworkDataSource {
    suspend fun getGoodsPage(params: GoodsSearchRequest): NetworkResponse<NetworkPageData<Goods>>
    suspend fun getGoodsInfo(id: String): NetworkResponse<Goods>
}
  • 实现 GoodsNetworkDataSourceImpl.kt
kotlin
class GoodsNetworkDataSourceImpl @Inject constructor(
    private val goodsService: GoodsService
) : BaseNetworkDataSource(), GoodsNetworkDataSource {

    override suspend fun getGoodsPage(params: GoodsSearchRequest) =
        goodsService.getGoodsPage(params)

    override suspend fun getGoodsInfo(id: String) =
        goodsService.getGoodsInfo(id)
}

3. Repository(core/data/repository/GoodsRepository.kt

kotlin
class GoodsRepository @Inject constructor(
    private val goodsNetworkDataSource: GoodsNetworkDataSource
) {
    fun getGoodsPage(params: GoodsSearchRequest): Flow<NetworkResponse<NetworkPageData<Goods>>> =
        flow { emit(goodsNetworkDataSource.getGoodsPage(params)) }
            .flowOn(Dispatchers.IO)

    fun getGoodsInfo(id: String): Flow<NetworkResponse<Goods>> =
        flow { emit(goodsNetworkDataSource.getGoodsInfo(id)) }
            .flowOn(Dispatchers.IO)
}

通过这条链路,Feature ViewModel 只需注入 GoodsRepository 即可发起网络请求,而无须了解 Retrofit/OkHttp 的细节。

4. 依赖注入(core/network/di/ServiceModule.kt & core/network/di/DataSourceModule.kt

kotlin
// ServiceModule.kt
@Provides
@Singleton
fun provideGoodsService(retrofit: Retrofit): GoodsService =
    retrofit.create(GoodsService::class.java)
kotlin
// DataSourceModule.kt
@Provides
@Singleton
fun provideGoodsNetworkDataSource(goodsService: GoodsService): GoodsNetworkDataSource =
    GoodsNetworkDataSourceImpl(goodsService)

记得在新增 Service/DataSource 时同步更新两个 Module,否则 Hilt 无法注入。

依赖注入

  • ServiceModule:使用 Retrofit 创建所有 Service。
  • DataSourceModule:创建对应的 NetworkDataSource。
  • NetworkModule:提供 Retrofit、OkHttp、Json、LoggingInterceptor。

所有模块都 @InstallIn(SingletonComponent::class),因此可在任意 Hilt 作用域中注入。

添加新接口流程(以 Cart 为例)

  1. 定义实体/请求体core/model
    kotlin
    @Serializable data class AddCartRequest(val goodsId: Long, val count: Int)
  2. Servicecore/network/service/CartService.kt
    kotlin
    interface CartService {
        @POST("cart/add")
        suspend fun addToCart(@Body request: AddCartRequest): NetworkResponse<Unit>
    }
  3. DataSourcecore/network/datasource/cart
    kotlin
    // CartNetworkDataSource.kt
    interface CartNetworkDataSource {
        suspend fun addToCart(request: AddCartRequest): NetworkResponse<Unit>
    }
    kotlin
    // CartNetworkDataSourceImpl.kt
    class CartNetworkDataSourceImpl @Inject constructor(
        private val cartService: CartService
    ) : BaseNetworkDataSource(), CartNetworkDataSource {
        override suspend fun addToCart(request: AddCartRequest) =
            cartService.addToCart(request)
    }
  4. DI 注册
    kotlin
    // ServiceModule.kt
    @Provides
    @Singleton
    fun provideCartService(retrofit: Retrofit): CartService =
        retrofit.create(CartService::class.java)
    kotlin
    // DataSourceModule.kt
    @Provides
    @Singleton
    fun provideCartNetworkDataSource(cartService: CartService): CartNetworkDataSource =
        CartNetworkDataSourceImpl(cartService)
  5. Repositorycore/data/repository/CartRepository.kt
    kotlin
    class CartRepository @Inject constructor(
        private val cartNetworkDataSource: CartNetworkDataSource
    ) {
        fun addToCart(request: AddCartRequest): Flow<NetworkResponse<Unit>> =
            flow { emit(cartNetworkDataSource.addToCart(request)) }
                .flowOn(Dispatchers.IO)
    }
  6. ViewModel/UseCase
    注入 CartRepository,直接调用对应方法并结合 BaseNetWorkViewModel 处理三态 UI。

调试与日志

  • HttpLoggingInterceptor:默认 debug 打印 BODY,release 关闭;可根据需求调整级别。
  • Chucker:在 debug 包内会自动弹出通知,可查看每一次请求的 Header/Body。如果需要禁用,直接移除 debugImplementation(libs.chucker) 或在 NetworkModule 中移除 addInterceptor(ChuckerInterceptor...)

关联 DataStore & Auth

AuthInterceptor 使用 AuthStoreDataSource 读取 token,因此必须先在 DataStore 层保存认证信息(如登录成功后调用 AuthStoreRepository.saveAuth())。一旦 token 变更,新的请求会自动携带最新的 Header。

常见定制点

  • 切换 BaseUrl:修改 buildConfigField("BASE_URL", "...") 或使用多环境构建(flavor/BuildConfig)。
  • 超时设置:在 NetworkModule.provideOkHttpClient 中调整 connectTimeout/readTimeout 等参数。
  • 证书/代理:在 OkHttp Builder 中追加 sslSocketFactoryproxy 等配置。
  • 错误处理:网络层只负责发请求,错误处理在 core/result 模块中进行(ResultHandler)。如需统一拦截 401,可在拦截器中判断状态码并触发登出。

通过这种模块化结构,网络请求的新增/修改都集中在 core/network + core/data,上层 Feature 只需调用 Repository 即可,极大地提高了可维护性和可测试性。

  • 相关依赖版本可在 gradle/libs.versions.toml 中查看(okhttplogging-interceptorchucker 条目都附带官方链接)。