我的 Android 项目中有 Hilt DI 框架。我还有改造和 ApiNetworkModule 用于获取单例改造对象:
@Module
@InstallIn(SingletonComponent.class)
public class ApiNetworkModule {
...
@Singleton
@Provides
public Retrofit provideRetrofit(
OkHttpClient okHttpClient,
Gson gson,
SharedPrefManager sharedPrefManager
) {
return new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(sharedPrefManager.getUrl())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
...
}
一般来说它工作得很好,但我注意到在
sharedPrefManager
中更新url时,改造对象不知道它并使用旧的url。只有在关闭-打开应用程序后才会完全更新。有没有办法以编程方式重新初始化 Retrofit
单例?或者如何正确处理?
接收修改后的 URL 的 Retrofit 对象的方法是去掉 @Singleton 。如果删除@Singleton,则可以通过将修改后的URL应用于sharedPreferences来创建Retrofit对象,因为Retrofit对象是在创建存储库时创建并注入的。
@Module
@InstallIn(SingletonComponent.class)
public class ApiNetworkModule {
...
@Provides
public Retrofit provideRetrofit(
OkHttpClient okHttpClient,
Gson gson,
SharedPrefManager sharedPrefManager
) {
return new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(sharedPrefManager.getUrl())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
...
}
我们推荐这种方法,因为你想要的是一种在 URL 修改时创建并注入新对象的方法,而不是只存在于单例组件依赖树中的 Retrofit 对象。
--------------------更新---------------------------------------- -------------
使用SingletonComponent.class时,无法初始化,因为其生命周期与Application相同。首先,正如我所说,如果你删除@Singleton,你可以转换,但是重新创建有问题,所以我将告诉你如何使用Interceptor更改Api Url地址。
class HostSelectionInterceptor: Interceptor {
private val baseHost = TestApp.getPreference().getRestUrl().toHttpUrl().host
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
if (TestApp.getPreference().isTestMode()) {
val convertUrl = when (request.url.host) {
baseHost -> {
APIClient.BASE_TEST_REST_URL
}
else -> baseHost
}
val newUrl = request.url.newBuilder().host(convertUrl.toHttpUrl().host).build()
val newRequest = request.newBuilder().url(newUrl).build()
return chain.proceed(newRequest)
}
return chain.proceed(request)
}
}
网络.类
private val okHttpClient: OkHttpClient by lazy {
OkHttpClient.Builder()
.addInterceptor(logInterceptor)
.addInterceptor(HostSelectionInterceptor())
.connectTimeout(TIMEOUT_CONNECT, TimeUnit.SECONDS)
.readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
.writeTimeout(TIMEOUT_WRITE, TimeUnit.SECONDS)
.build()
}
拦截器可以拦截服务器请求和响应并执行所需的操作。上面的示例是在测试模式下请求将 Base Url 更改为 Test Url 的示例。
我希望这有帮助。