2016-11-21 68 views
0

我对DI一般很陌生,特别是Dagger。我目前有这个问题,我还没有设法找到解决方案。比方说,我有一个AppModule为用户提供访问令牌放入请求头现在模块中的匕首2更新对象

@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(); 
    } 
} 

和刚刚获得访问令牌和动态创建的改造/ OkHttp客户端,但这似乎不是我的权利。任何人都有解决方案?

回答

1

您的AuthenticationManager解决方案看起来比较适合我,或者您可以使用您编写的AtomicReference<String>或一般Holder<String>类。

你最好的选择就是让像一个@Named("access-token") String或自定义限定符注解@AccessToken String可通过应用程序,与使用模块状态总是返回最新的值非单身@Provides方法,但有一些的问题太:

  1. 这里没有自然的setter,不像你的AuthenticationManager。除非在依赖关系图中有其他可用的值,您可以在@Provides方法中接受,否则您必须注入Module或可以访问Module的可变字段的东西。这听起来不容易理解。

  2. 字符串不可变,所以如果你想要一个返回最新值的对象,你总是需要一个@AccessToken Provider<String>而不是@AccessToken String。 Dagger并不便于制作只能注入提供者的密钥,因此除非您完全控制此代码库或者可以设置静态分析检查,否则这将会很脆弱并容易被滥用。

  3. 您对Dagger解决方案的线程安全性和同步的控制稍微有限,而您自己的可设置的持有者具有您可以自己定义的语义。

  4. 在单元测试中,如果您希望在不创建自定义的测试Dagger组件的情况下更改Provider的值,则必须创建可设置的Provider类。这看起来很像AtomicReference,Holder或者你的AuthenticationManager,你也可以从其中的一个开始。

作为最后的选择,如果你能代表一个要求,因为一个短暂的不可变对象的状态,你可能更喜欢创造那些故意限制寿命的一个。通过这种方式,您可以使用短期对象而不是单例,并且不必担心稍后更新现有实例。如果(例如)您希望重试使用旧的访问令牌,而使用新的访问令牌创建新的请求,则这可能也具有吸引人的重试语义。如果此选项对您有吸引力,请查看Dagger子组件:您可以为每个请求创建一个新的具有新的不可变模块的子组件,然后可以完全访问您的对象图,包括访问临时访问令牌和状态,是必要的。

+0

非常详细的答案,谢谢!我说“AuthenticationManager”解决方案看起来不正确的原因是因为它增加了应用程序的复杂性。比方说,我有一堆4个活动,用户可以在任何活动中登录。现在,当他们在堆栈顶部登录时,他们回去时,我必须检查'AuthenticationManager'并在必要时重新创建Retrofit/OkHttp的另一个实例。不幸的是,这太复杂了,如果做得不对,可能会带来更多麻烦。这就是为什么我正在寻找一种解决方案,我可以为客户使用单例。 –