Dagger2一个模块,用于两个不同的作用域 [英] Dagger2 one module for two different scopes

查看:140
本文介绍了Dagger2一个模块,用于两个不同的作用域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my app i have an ApplicationScope which provides me with stuff like context and shared prefs. 2 sub components, LoggedInComponent and LoggedOutComponent. Those 2 subcomponents have other subcomponents which are less relevant to the issue.

我有一个NetworkModule创建了我的改造实例。
这两个子组件都需要NetworkModule,但由于基本URL和其他设置可能会更改,因此改造过程可能会更改。

I have a NetworkModule which creates my retrofit instance. Both subcomponents need the NetworkModule but the retrofit might change during the login because the base url and other settings might change.

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

I was wondering which approach it is better to take: 1. Give both LoggedIn and LoggedOut sub components and the NetworkModule the same scope so both sub components can use this module. Feels a bit hacky and wrong usage of scopes. 2. Put network module in the AppComponent with ApplicationScope. Also wrong usage of scope because network module is recreated so it cannot have same scope and also each recreation will cause the AppComponent and its subcomponents to be recreated.

您将做什么?也许有更好的解决方案?

What would you do? maybe there is a better solution?

推荐答案

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

You don't want LoggedInComponent and LoggedOutComponent to have differing network behavior, and you don't necessarily need network behavior to be consistent across the lifetime of LoggedInComponent or LoggedOutComponent, so it doesn't make sense for you to have them bind NetworkModule separately. I think it makes sense to make them available through AppComponent. Remember that not everything in AppComponent needs to have ApplicationScope: You can make unscoped bindings in AppComponent, which instructs Dagger to re-fetch or re-create the requested object every time.

特别是,我将NetworkModule绑定到AppComponent的 subcomponent 中,您可以在NetworkModule配置每次更改时重新创建。这不仅可以让您封装一些网络详细信息(请参见子组件封装),但是如果您要查找的话,它也可以让您在整个网络绑定中利用依赖注入。

Specifically, I would bind NetworkModule into a subcomponent of AppComponent, which you can recreate every time the NetworkModule configuration changes. Not only would this let you encapsulate some of the network details (see "subcomponents for encapsulation" in the Dagger User's Guide), but it would also let you take advantage of dependency injection throughout your network bindings if that's what you're looking for.

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

To ensure that you're getting the correct current NetworkComponent, you could create a NetworkManager that is singleton-bound (ApplicationScope). You can use that to hold the latest 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 )。当响应返回告诉您更新基本URL时,您可以注入NetworkManager,调用 updateSettings ,突然有新的Retrofit请求将返回您的新实例。 (不过请注意,改造旧的实例可能仍然存在,但是只要更改属于现有实例的依赖项,就会遇到问题。)

With this, most of your code in AppComponent, LoggedInComponent, and LoggedOutComponent can just inject a Retrofit (or Provider<Retrofit>) whenever they need to make a request. When a response comes back that tells you to update your base URL, you can inject a NetworkManager, call updateSettings, and suddenly new requests for Retrofit will return your new instance. (Note however that old instances to Retrofit may still stick around, but you'll have that problem any time you're changing a dependency belonging to an existing instance.)

ps如果NetworkModule足够轻便,或者具有足够的绑定,则可以选择直接将NetworkModule放到ApplicationComponent上,并简单地让NetworkManager保留当前的Retrofit实例等。您必须根据所需的绑定数进行判断与 provideRetrofit 一样通过,而不是要封装或隐藏在子组件中的绑定数。

p.s. If NetworkModule is lightweight enough, or has consistent-enough bindings, you might opt to put NetworkModule directly onto ApplicationComponent and simply have NetworkManager hold the current Retrofit instance etc. You'll have to make that judgment call based on the number of bindings you want to pass through as provideRetrofit does, compared to the number of bindings you'd want to encapsulate or hide away in a subcomponent.

这篇关于Dagger2一个模块,用于两个不同的作用域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆