Dondump
Dondump

Reputation: 39

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

Considering the following scenario:

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

I've defined a SessionModule to inject SessionManager whenever HasSession or HasCredentials is requested for injection:

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

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

Then I've defined the corresponding component:

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

    public HasSession getSessionProvider();

    public HasCredentials getCredentialsProvider();

}

getSessionProvider and getCredentialsProvider will create/return two different SessionManager instance.

I would like a single instance of SessionManager to be created and returned whenever I call getSessionProvider or getCredentialsProvider. How can I acomplish that with Dagger 2?

Upvotes: 0

Views: 835

Answers (2)

Dondump
Dondump

Reputation: 39

I found the solution to this problem: Just defining a Singleton provider for SessionManager:

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

Upvotes: 0

Jake Wharton
Jake Wharton

Reputation: 76075

You need to do two separate things:

  1. Scope the binding so that there's only one instance.
  2. Alias the scoped binding to the alternate types.

First, scope the binding:

@Qualifier
private @interface Scoped {}

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

Second, alias the scoped binding:

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

Note: This will not prevent modules in this component from using the unscoped SessionManager, so be careful.

An easy way to workaround that is to use a @Component.Builder and use @BindsInstance to pass in a single instance of SessionManager that's effectively scoped (and thus eliminating the need for the first code snippet above and allowing your original code to work).

Upvotes: 2

Related Questions