在过去的几个月里,我一直在使用Dagger / Retrofit,并且已经看到了为api实现ApiModule类的常见模式.这些ApiModules通常看起来像这样:
@Provides @Singleton Client provideClient(OkHttpClient client) {
return new OkClient(client);
}
@Provides @Singleton Endpoint provideEndpoint() {
return "release".equalsIgnoreCase(BuildConfig.BUILD_TYPE)
? Endpoints.newFixedEndpoint(PRODUCTION_URL, "Foo Production Url")
: Endpoints.newFixedEndpoint(STAGING_URL, "Foo Staging Url");
}
@Provides @Singleton Converter provideConverter(Gson gson) {
return new GsonConverter(gson);
}
@Provides @Singleton RestAdapter provideRestAdapter(Endpoint endpoint, Client client,
Converter converter) {
return new RestAdapter.Builder()
.setClient(client)
.setEndpoint(endpoint)
.setConverter(converter)
.setLogLevel(BuildConfig.DEBUG
? RestAdapter.LogLevel.FULL
: RestAdapter.LogLevel.NONE)
.build();
}
@Provides @Singleton FooApi provideFooApi(RestAdapter restAdapter) {
return restAdapter.create(FooApi.class);
}
但要清理这个,为什么不这样做:
@Provides @Singleton Client provideClient(OkHttpClient client) {
return new OkClient(client);
}
@Provides @Singleton Converter provideConverter(Gson gson) {
return new GsonConverter(gson);
}
@Provides @Singleton FooApi provideFooApi(Client client, Converter converter) {
return new RestAdapter.Builder()
.setClient(client)
.setEndpoint("release".equalsIgnoreCase(BuildConfig.BUILD_TYPE)
? Endpoints.newFixedEndpoint(PRODUCTION_URL, "Foo Production Url")
: Endpoints.newFixedEndpoint(STAGING_URL, "Foo Staging Url"))
.setConverter(converter)
.setLogLevel(BuildConfig.DEBUG
? RestAdapter.LogLevel.FULL
: RestAdapter.LogLevel.NONE)
.build()
.create(FooApi.class);
}
这样做是否有任何缺点或我违反了一些Dagger合同?我问,因为有些情况下我需要在一个项目中使用多个API …像上面的第二个例子一样设置它,使这成为可能.
解决方法:
这样做有三个原因:
>通过分裂这两者,你正在创造一个关注点的分离.如何将RestAdapter实例化并放入图形中,与将服务接口的实例放入图形的方式完全不同.在这里,您碰巧将它们放在同一个模块中,但没有理由它们不能在单独的模块中,甚至不能在不同组件的库中使用它们.
>单独的提供程序允许您覆盖覆盖模块中的一个或两个以自定义行为,而无需知道对方的使用方式或来自何处.
例如,如果要在运行集成测试时启用不同的行为,则可以提供不同的RestAdapter实例.
@Provides @Singleton RestAdapter provideTestRestAdapter() {
return new RestAdapter.Builder()
.setEndpoint(Endpoints.newFixedEndpoint("http://mycomputer.local/api"))
.setLogLevel(FULL)
.build();
}
在覆盖模块中具有此功能意味着您不必更改创建服务实例的位置.
>最后,最简单的说,也许你有多个服务接口.您不应该创建多个RestAdapter实例(除非它们用于不同的端点).
@Provides @Singleton AccountService provideAccountService(RestAdapter ra) {
return ra.create(AccountService.class);
}
@Provides @Singleton TweetService provideTweetService(RestAdapter ra) {
return ra.create(TweetService.class);
}
@Provides @Singleton DirectMessageService provideDirectMessageService(RestAdapter ra) {
return ra.create(DirectMessageService.class);
}