如何为Dagger的@BindsInstance对象设置默认回退值?
问题描述
我们原有Dagger API结构如下:
// 原有API代码 @Component(modules = ApiManagerModule.class) public interface ApiComponent { @Component.Builder interface Builder { ApiComponent build(); } ApiManager apiManager(); } @Module public interface ApiManagerModule { @Binds ApiManager bindApiManager(ApiManagerImpl impl); } // 用户原有使用方式 ApiComponent apiComponent = DaggerApiComponent.builder().build(); ApiManager apiManager = apiComponent.apiManager(); apiManager.doApiThings();
出于需求,我们给API添加了ApiOptions选项对象,修改后的代码如下:
@Component(modules = ApiManagerModule.class) public interface ApiComponent { @Component.Builder interface Builder { ApiComponent build(); // 新增方法 @BindsInstance Builder setApiOptions(ApiOptions options); } ApiManager apiManager(); } @Module public interface ApiManagerModule { @Binds ApiManager bindApiManager(ApiManagerImpl impl); } // 新增的ApiOptions类 @AutoValue public abstract class ApiOptions { //... @AutoValue.Builder public abstract static class Builder { //... } } // 用户现在必须这样使用 ApiComponent apiComponent = DaggerApiComponent.builder() .setApiOptions( ApiOptions.builder() /* 设置选项 */ .build()); ApiManager apiManager = apiComponent.apiManager(); apiManager.doApiThings();
但这属于破坏性变更,已集成的用户必须修改代码来设置@BindsInstance的选项对象。我们希望实现:当用户未调用setApiOptions()时,Dagger自动创建并提供默认的ApiOptions实例,允许用户继续使用原有无参数的构建方式:
ApiComponent apiComponent = DaggerApiComponent.builder() // 未调用setApiOptions时,自动使用默认实例 .build(); ApiManager apiManager = apiComponent.apiManager(); apiManager.doApiThings();
请问是否可以为@BindsInstance的选项对象提供这样的默认回退值?
解决方案
可以实现这个需求,核心思路是利用Dagger的依赖优先级:@BindsInstance绑定的实例优先级高于Module中@Provides提供的实例。具体步骤如下:
添加提供默认
ApiOptions的Module
新建一个模块(或修改现有模块为抽象类),添加@Provides方法返回默认配置的ApiOptions实例:@Module public class ApiOptionsModule { @Provides static ApiOptions provideDefaultApiOptions() { // 返回预定义的默认配置 return ApiOptions.builder() /* 设置默认选项参数 */ .build(); } }修改Component配置
将新的ApiOptionsModule加入Component的模块列表,同时保留@BindsInstance的setApiOptions方法:@Component(modules = {ApiManagerModule.class, ApiOptionsModule.class}) public interface ApiComponent { @Component.Builder interface Builder { ApiComponent build(); @BindsInstance Builder setApiOptions(ApiOptions options); } ApiManager apiManager(); }逻辑验证
- 当用户主动调用
setApiOptions()传入自定义实例时,Dagger会优先使用这个绑定的实例,忽略Module中的默认值 - 当用户不调用
setApiOptions()时,Dagger会自动从ApiOptionsModule中获取默认的ApiOptions实例
- 当用户主动调用
这种方式既实现了自定义配置的新增功能,又完全兼容原有API的使用方式,已集成的用户无需修改代码即可正常使用。如果ApiOptions的默认构建需要其他依赖,也可以在provideDefaultApiOptions()方法中添加对应参数,Dagger会自动注入所需依赖。
内容的提问来源于stack exchange,提问作者Q. Jing
相关产品推荐
相关产品推荐

