Dagger2一个模块用于两个不同的范围

时间:2017-03-30 19:20:52

标签: android dagger-2 dagger

在我的应用程序中,我有一个ApplicationScope,它为我提供了上下文和共享首选项等内容。 2个子组件,LoggedInComponent和LoggedOutComponent。 这2个子组件具有与该问题不太相关的其他子组件。

我有一个NetworkModule来创建我的改造实例。 两个子组件都需要NetworkModule,但在登录期间可能会更改改装,因为基本URL和其他设置可能会更改。

我想知道哪种方法更好: 1.为LoggedIn和LoggedOut子组件以及NetworkModule提供相同的范围,以便两个子组件都可以使用此模块。感觉有点hacky和错误使用范围。 2.使用ApplicationScope将网络模块放入AppComponent中。同样错误地使用了作用域,因为网络模块被重新创建,因此它不能具有相同的作用域,并且每次重新创建都会导致重新创建AppComponent及其子组件。

你会做什么?也许有更好的解决方案?

1 个答案:

答案 0 :(得分:1)

您不希望LoggedInComponent和LoggedOutComponent具有不同的网络行为,并且您不一定需要网络行为在LoggedInComponent或LoggedOutComponent的生命周期内保持一致,因此将它们绑定是没有意义的NetworkModule分开。我认为通过AppComponent使它们可用是有意义的。请记住,并非AppComponent中的所有内容都需要具有ApplicationScope:您可以在AppComponent中进行无范围绑定,指示Dagger每次都重新获取或重新创建所请求的对象。

具体来说,我将NetworkModule绑定到AppComponent的子组件,每次NetworkModule配置更改时都可以重新创建。这不仅可以让您封装一些网络详细信息(请参阅Dagger用户指南中的"subcomponents for encapsulation"),但如果您正在寻找的话,它还可以让您在整个网络绑定中利用依赖注入。

为了确保您获得正确的当前 NetworkComponent,您可以创建一个单独绑定的NetworkManager(ApplicationScope)。您可以使用它来保存最新的NetworkComponent。

@Module(subcomponents={NetworkComponent.class})
public abstract class ApplicationModule {
  /** Unscoped. Fetch this fresh from NetworkComponentHolder each time. */
  @Provides Retrofit provideRetrofit(NetworkManager manager) {
    return manager.getNetworkComponent().getRetrofit();
  }
}

@ApplicationScope public class NetworkManager {
  private final Provider<NetworkComponent.Builder> builderProvider;
  private NetworkComponent currentComponent;

  @Inject public NetworkComponentHolder(
      Provider<NetworkComponent.Builder> builderProvider) {
    this.builderProvider = builderProvider;
    currentComponent = builderProvider.get()
        .withNetworkModule(getDefault())
        .build();
  }

  public void updateSettings(String baseUrl) {
    currentComponent = builderProvider.get()
        .withNetworkModule(new NetworkModule(baseUrl))
        .build();
  }

  public NetworkComponent getNetworkComponent() {
    return currentComponent;
  }
}

有了这个,AppComponent,LoggedInComponent和LoggedOutComponent中的大多数代码只需在需要发出请求时注入Retrofit(或Provider<Retrofit>)。当响应回来告诉您更新基本URL时,您可以注入NetworkManager,调用updateSettings,然后突然新的Retrofit请求将返回您的新实例。 (但请注意,Retrofit的旧实例可能仍然存在,但是当您更改属于现有实例的依赖项时,您将遇到该问题。)

P.S。如果NetworkModule足够轻量级,或者具有足够一致的绑定,您可以选择将NetworkModule直接放到ApplicationComponent上,只需让NetworkManager保存当前的Retrofit实例等。您必须根据所需的绑定数量进行判断调用通过provideRetrofit传递,与您想要在子组件中封装或隐藏的绑定数相比较。