You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中Kotlin类如何传递Context至ApiClient添加设备UUID请求头

我来给你梳理下可行的解决方案,核心是让你的单例ApiClient能拿到安全的Context,同时避免内存泄漏问题:

第一步:修改ApiClient的构造与单例逻辑

首先调整ApiClient的结构,让它能接收Context并保存Application Context(这是关键,避免持有Activity/Fragment Context导致内存泄漏),同时在拦截器中调用你的UUID扩展方法:

class ApiClient private constructor(private val appContext: Context) {
    private val apiServices: ApiServices

    init {
        // Gson配置保持不变
        val gson = GsonBuilder()
            .setLenient()
            .create()

        // 日志拦截器配置保持不变
        val loggingInterceptor = HttpLoggingInterceptor()
        loggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE

        // OkHttpClient构建器:添加UUID请求头
        val clientBuilder = OkHttpClient.Builder()
            .addInterceptor(loggingInterceptor)
            .addInterceptor { chain ->
                val originalRequest = chain.request()
                // 调用扩展方法获取设备UUID
                val deviceUuid = appContext.getDeviceUUID()
                // 构建新请求并添加uuid头
                val newRequest = originalRequest.newBuilder()
                    .addHeader("uuid", deviceUuid)
                    .build()
                chain.proceed(newRequest)
            }
            .readTimeout(NETWORK_CONNECTIONS_TIME, TimeUnit.SECONDS)
            .writeTimeout(NETWORK_CONNECTIONS_TIME, TimeUnit.SECONDS)
            .connectTimeout(NETWORK_CONNECTIONS_TIME, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)

        val client = clientBuilder.build()

        // Retrofit配置保持不变
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
            .build()

        apiServices = retrofit.create(ApiServices::class.java)
    }

    companion object {
        @Volatile
        private var apiClient: ApiClient? = null

        // 提供带Context的单例获取方法,确保线程安全
        fun getInstance(context: Context): ApiClient {
            return apiClient ?: synchronized(this) {
                apiClient ?: ApiClient(context.applicationContext).also { apiClient = it }
            }
        }
    }

    // 暴露ApiServices供外部调用
    fun getApiServices(): ApiServices = apiServices
}

第二步:全局初始化ApiClient

建议在你的Application类的onCreate方法中完成初始化,这样整个应用生命周期内只创建一次实例,且确保拿到的是全局安全的Application Context:

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        // 初始化ApiClient,传入Application Context
        ApiClient.getInstance(this)
    }
}

别忘了在AndroidManifest.xml中配置你的Application类:

<application
    android:name=".MyApp"
    ...>
    ...
</application>

第三步:使用ApiClient

之后在需要调用接口的地方,直接获取实例即可:

val apiServices = ApiClient.getInstance(applicationContext).getApiServices()
// 调用接口方法示例
apiServices.yourApiMethod().subscribe(...)

关键注意点

  • 必须用applicationContext:如果传入Activity/Fragment的Context,当组件销毁时,单例ApiClient仍持有引用会导致内存泄漏,Application Context的生命周期与应用一致,是安全选择。
  • 双重检查锁机制:@Volatile+synchronized确保多线程环境下不会创建多个ApiClient实例。

这样修改后,你的所有请求都会自动带上设备UUID请求头,同时完美解决了Context传入的问题。

内容的提问来源于stack exchange,提问作者KokoBand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:03:26