如何让两个不同的@Provider 在 Dagger 2 中注入相同的@Singleton?

How do I make two different @Providers inject the same @Singleton in Dagger 2?

考虑以下情况:

public class SessionManager implements HasSession, HasCredentials{
/**implementation here*/
}

我已经定义了一个 SessionModule 来在请求注入 HasSession 或 HasCredentials 时注入 SessionManager:

@Module
public abstract class SessionModule {
    @Provides @Singleton static HasSession hasSession(SessionManager sessionManager){
        return sessionManager;
    };

    @Provides @Singleton static HasCredentials hasCredentials(SessionManager sessionManager){
        return sessionManager;
    };
}

然后我定义了相应的组件:

@Component(modules={SessionModule.class})
@Singleton
public interface MyComponent {

    public HasSession getSessionProvider();

    public HasCredentials getCredentialsProvider();

}

getSessionProvider 和 getCredentialsProvider 将 create/return 两个不同的 SessionManager 实例。

我希望在调用 getSessionProvider 或 getCredentialsProvider 时创建并返回 SessionManager 的 单个 实例。我怎样才能用 Dagger 2 完成它?

您需要做两件事:

  1. 限定绑定的范围,以便只有一个实例。
  2. 将作用域绑定别名为替代类型。

首先,确定绑定范围:

@Qualifier
private @interface Scoped {}

@Provides @Singleton
@Scoped SessionManager scopeSessionManager(SessionManager manager) {
  return manager;
}

其次,为范围绑定设置别名:

@Binds abstract HasSession bindHasSession(@Scoped SessionManager manager);
@Binds abstract HasCredentials bindHasCredentials(@Scoped SessionManager manager);

注意:这不会阻止此组件中的模块使用未限定范围的SessionManager,所以要小心。

一种简单的变通方法是使用 @Component.Builder 并使用 @BindsInstance 传入 SessionManager 的单个实例,这 有效 范围(因此消除了对上面第一个代码片段的需要并允许您的原始代码工作)。

我找到了这个问题的解决方案:只需为 SessionManager 定义一个 Singleton 提供程序:

@Provides @Singleton
static SessionManager sessionManager(/*dependencies here*/){
    return new SessionManager(/**dependencies*/);
}