MVP+Retrofit2+Dagger2:如何向Repository传递可更新的ApiService
这问题我之前帮不少开发者解决过,核心矛盾就是单例Repository依赖的MailService是静态绑定的,没法随着配置更新动态切换。给你几个实用的解决方案,按改动成本从低到高来:
解决方案1:注入
Provider<MailService>替代直接注入MailService Dagger的Provider接口就是专门解决这种需要动态获取实例的场景——它的get()方法每次都会从Dagger容器中获取最新的实例。具体步骤如下:
- 修改Repository的依赖注入方式
把原来直接注入MailService改成注入Provider<MailService>,每次调用接口时都通过Provider获取最新实例:
@Singleton public class MyRepository { private final Provider<MailService> mailServiceProvider; @Inject public MyRepository(Provider<MailService> mailServiceProvider) { this.mailServiceProvider = mailServiceProvider; } public void fetchInboxMails() { // 每次调用都拿最新配置的MailService MailService latestMailService = mailServiceProvider.get(); latestMailService.getInbox().enqueue(new Callback<List<Mail>>() { // 回调逻辑... }); } }
- 确保Dagger能提供最新的MailService实例
在你的Dagger模块中,保证每次请求MailService时,都是基于最新配置创建的Retrofit生成的:
@Module public class ApiModule { private final RestApiFactory restApiFactory; public ApiModule(RestApiFactory restApiFactory) { this.restApiFactory = restApiFactory; } @Provides @Singleton public MailService provideMailService() { // 每次调用都会触发RestApiFactory用最新配置创建Retrofit return restApiFactory.createRetrofit().create(MailService.class); } }
这样每次调用Provider.get(),都会重新执行provideMailService()方法,拿到更新配置后的MailService。
解决方案2:通过
RestApiFactory封装MailService的获取 既然你已经实现了RestApiFactoryImpl来动态创建Retrofit,可以让工厂直接维护当前有效的MailService实例,Repository注入工厂后,每次从工厂获取最新实例:
- 优化RestApiFactory接口与实现
public interface RestApiFactory { // 添加获取当前有效MailService的方法 MailService getCurrentMailService(); // 保留原有的配置更新方法 void updateApiConfig(ApiConfig newConfig); } public class RestApiFactoryImpl implements RestApiFactory { private MailService currentMailService; @Override public void updateApiConfig(ApiConfig newConfig) { // 根据新配置重建Retrofit OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(newConfig.getTimeout(), TimeUnit.SECONDS) .build(); Retrofit newRetrofit = new Retrofit.Builder() .baseUrl(newConfig.getBaseUrl()) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build(); // 更新当前的MailService实例 currentMailService = newRetrofit.create(MailService.class); } @Override public MailService getCurrentMailService() { // 初始化兜底:如果还没配置过,用默认值创建一次 if (currentMailService == null) { updateApiConfig(getDefaultApiConfig()); } return currentMailService; } private ApiConfig getDefaultApiConfig() { // 返回默认的baseUrl、超时时间等配置 return new ApiConfig("https://default.mail.com", 10); } }
- Repository中通过工厂获取MailService
@Singleton public class MyRepository { private final RestApiFactory restApiFactory; @Inject public MyRepository(RestApiFactory restApiFactory) { this.restApiFactory = restApiFactory; } public void fetchSentMails() { MailService latestMailService = restApiFactory.getCurrentMailService(); latestMailService.getSentBox().enqueue(...); } }
这个方案的优势是把API实例的管理完全封装在工厂里,Repository只需要专注业务逻辑,不需要了解Dagger的细节,后续扩展其他Service也更方便。
方案对比与注意事项
- 如果你已经深度依赖Dagger的注入体系,方案1改动最小,适合快速解决问题;
- 如果你希望API配置与业务逻辑完全解耦,方案2更符合单一职责原则,可维护性更强;
- 不管用哪种方案,都要保证
updateApiConfig()方法的线程安全性——比如加锁或者用原子类,避免多线程下拿到半初始化的MailService实例。
内容的提问来源于stack exchange,提问作者ip696
相关产品推荐
相关产品推荐

