我对DI一般都很陌生,尤其是Dagger。我目前遇到了这个问题,但我还没有找到解决方案。假设我有一个AppModule
来为Retrofit客户端提供放入请求标头的访问令牌
@Module
public class AppModule {
@Provides
@Singleton
SharedPref provideSharedPreferences(Application application) {
return new SharedPref(application);
}
@Provides
@Singleton
AuthInterceptor provideAuthenticationInterceptor(SharedPref sharedPref) {
return new AuthInterceptor(sharedPref.getAccessToken());
}
@Provides
@Singleton
OkHttpClient provideHttpClient(AuthInterceptor authInterceptor) {
return new OkHttpClient.Builder()
.addInterceptor(authInterceptor)
.build();
}
@Provides
@Singleton
DribbbleApi provideClient(OkHttpClient client, Gson gson) {
return new Retrofit.Builder()
.baseUrl(DribbbleApi.ENDPOINT)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
.create((DribbbleApi.class));
}
}
现在,当用户首次使用该应用时,SharedPreference
中的访问令牌不存在,因此我为其提供了默认值。但是一旦他们登录,访问令牌将保存到SharedPreference
,但我无法更新OkHttpClient
以接受新值,因为AuthInterceptor
已使用默认访问令牌创建应用的开始。
我在看这里有一些同样问题的问题,但似乎没有一个在我的案例中有用。我正在考虑使用这个模块:
public class AuthenticationManager {
private String accessToken;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String ac) {
this.accessToken = ac;
}
}
@Module
public class AuthenticationModule {
@Provides
@Singleton
AuthenticationManager provideAuthenticationManager() {
return new AuthenticationManager();
}
}
只需获取访问令牌并动态创建Retrofit / OkHttp客户端,但这对我来说似乎不对。任何人都有解决方案吗?
答案 0 :(得分:1)
您的AuthenticationManager解决方案对我来说很合适,或者您可以使用您编写的AtomicReference<String>
或一般Holder<String>
课程。
您最好的选择是通过应用程序提供类似@Named("access-token") String
或自定义限定符 - 注释@AccessToken String
的内容,使用非单身@Provides
方法,该方法始终使用模块状态返回最新值,但也存在许多问题:
这里没有自然的setter,与AuthenticationManager不同。除非通过您在@Provides
方法中可以接受的依赖关系图中的其他内容提供当前值,否则您将必须注入Module
或可以访问Module
的内容}可变字段。这听起来不容易理解。
字符串不可变,因此如果您想要一个返回最新值的对象,您将始终需要@AccessToken Provider<String>
而不是@AccessToken String
。 Dagger并不容易制作只能注入提供者的密钥,所以除非你完全控制这个代码库或者可以设置静态分析检查,否则这将是脆弱的,容易被滥用。
您对Dagger解决方案的线程安全性和同步性有一些更有限的控制权,而您自己的可设置的持有者具有您可以自己定义的语义。
在单元测试中,如果您希望在不创建自定义测试Dagger组件的情况下更改Provider的值,则必须创建一个可设置的Provider类。这看起来非常像AtomicReference,Holder或您的AuthenticationManager,您可以从其中一个开始。
作为最后的替代方案,如果您可以将请求的状态表示为一个短期不可变对象,您可能更愿意创建其中一个具有故意限制的生命周期。通过这种方式,您可以使用短期对象而不是单例,而不必担心以后更新现有实例。如果(例如)您希望使用旧访问令牌进行重试,但是要使用新访问令牌创建新请求,则这也可能具有吸引人的重试语义。如果此选项对您有吸引力,也可以查找Dagger子组件:您可以为每个请求创建一个带有新的不可变模块的新子组件,然后拥有对象图的完全访问权限,包括访问临时访问令牌和状态尽可能深的需要。