-1

I have singleton class that 2 other classes depend on: another singleton and a service. The problem is that in practice each of them receives a different instance of what's supposed to be a singleton. I'm trying to figure out why. Here's the gist of it:

The singleton dependency class:

@Singleton
public class SingletonDependency {
    @Inject
    public SingletonDependency() {
        // ...
    }
}

The other singleton which depends on it:

@Singleton
public class DependentClass {
    @Inject
    public DependentClass(SingletonDependency singletonDependency) {
        // ...
    }
}

The service which depends on it:

public class DependentService extends Service {
    @Inject SingletonDependency mSingletonDependency;

    @Override
    public void onCreate() {
        CoreInjector.INSTANCE.getCoreComponent().inject(this);
    }
}

I do not provide SingletonDependency explicitly since it has a @Inject constructor and Dagger2 takes care of it for me. Is this the root of it?


Edit:

Here's my injector:

public enum CoreInjector {

    INSTANCE;

    private CoreComponent mCoreComponent;

    public void init(Context context) { // called by the Application's onCreate()
        mCoreComponent = DaggerCoreComponent.builder()
                .coreModule(new CoreModule(context))
                .build();
    }

    public CoreComponent getCoreComponent() {
        return mCoreComponent;
    }
}

The Component itself:

@Singleton
@Component(modules = {CoreModule.class})
public interface CoreComponent {

    void inject(DependentService dependentService);

}

The Module itself doesn't provide the dependency explicitly, but once I do, everything works as expected - same instance.


Edit 2

Conclusions posted as an answer.

Itai Hanski
  • 8,540
  • 5
  • 45
  • 65
  • It looks like what you have should work. Can you confirm that you only ever create one Component (i.e. there aren't multiple injectors at play) and that your annotation is `javax.inject.Singleton`? – Jeff Bowman Nov 25 '15 at 16:43
  • I confirm both of those things. Furthermore, I tried to explicitly provide the `SingletonDependency` and when I did that, the same instance was used. But it's kind of a disappointing solution since the whole point of injected constructors is that you don't need to provide them. – Itai Hanski Nov 26 '15 at 07:42
  • Where do you create your component, can you provide code pls? – Ognyan Nov 26 '15 at 08:00
  • Such problems are usually caused by accidently creating two graphs. In your case it may be that init() is called twice somehow (hard to tell without more code). Also probably it is not best idea to use theCoreInjector. Please see http://stackoverflow.com/questions/33544922/dagger-2-injecting-singleton-with-lots-of-access-points/33579938#33579938 for example how to init the injector in your app and then access it conveniently. – Ognyan Nov 26 '15 at 11:00
  • It is absolutely not called twice, and in practice, your example goes through the exact same process - the `Application` initializes the component in its onCreate() method. I have to disagree with your recommendation since your solution forces my injected class to know the specific implementation of the `Application`, and for some reason it exposes a component. Granted, my solution doesn't protect against multiple calls to init (which do not occur - tested), but at least the injector's sole purpose to inject. Nothing else is exposed. I have a feeling this isn't what's causing the issue. – Itai Hanski Nov 26 '15 at 12:53
  • Figured it out. It was kind of silly mistake. See my edit. Thanks for trying :) – Itai Hanski Nov 29 '15 at 09:15
  • @ItaiHanski Stumbled across this question again; glad you got it solved! Please consider editing out your "Edit 2" above and adding it as a "self-answer" below. That way, it may be easier for future answerers to see that this question has a solution, and that way you may get credit for sharing your solution with the community. Cheers! – Jeff Bowman Mar 30 '16 at 17:22
  • @JeffBowman You're right. Done and done. – Itai Hanski Mar 31 '16 at 08:07

2 Answers2

2

I figured it out. My singleton class implements an interface, which is what my dependent classes depends on - not the implementation. I guess Dagger2 can't make that leap even though the implementation has a injected constructor.

Explicit @Provides method in a module was the only way to go.

Itai Hanski
  • 8,540
  • 5
  • 45
  • 65
1

Another possible cause of a singleton created many times is that @Singleton is enforced only by @Component. If a singleton is called by another @Component (or another instance of the same component), it will be re-created.

Eino Gourdin
  • 4,169
  • 3
  • 39
  • 67