[ACCEPTED]-How to resolve a circular dependency while still using Dagger2?-dagger

Accepted answer
Score: 52

The easy way out is to use Lazy<T> on one side.

Lazy<Foo> foo;

@Inject
Bar(Lazy<Foo> foo) {
    this.foo = foo;
}

// use foo.get(); when needed

0

Score: 3

After an excessive amount of thought and 16 talks with coworkers, we ended up doing 15 the following:

class Foo<T> extends FooWithoutDep<T> {
    @Inject Foo(Bar bar, OtherDep1 dep1, OtherDep2 dep2) {
        super(dep1, dep2);
        setBarDep(bar);
    }
}

class FooWithoutDep<T> {
    //Field declarations elided
    @Inject FooWithoutDep(OtherDep1 dep1, OtherDep2 dep2) {
        //Normal constructor stuff
    }
    void setBarDep(Bar bar) { this.bar = bar; }

    //The rest of the actual logic
}

class Bar {
    //Field declarations elided
    @Inject Bar(FooWithoutDep<Thing> foo, OtherDep3 dep3) {
        this.foo = foo;
        this.foo.setBarDep(this);
        this.dep3 = dep3;
    }

    //Code that uses Foo and the other dependencies
}

Explaining this -- we moved 14 the actual logic of Foo into a parent class 13 (FooWithoutDep), that took the circular 12 dependency as a settable field rather than 11 a constructor parameter. Then the original 10 class just contained a constructor that 9 took the circular dependency and called 8 the setter. The other class, Bar, depended 7 on the parent (FooWithoutDep), and called 6 the setter explicitly, passing itself (this). This 5 enables all the existing references to the 4 class to remain the same, while still using 3 Dagger to inject all the dependencies.

This 2 seemed confusing enough to be worth writing 1 up here.

Score: 1

This is how I resolved it, without parent 6 classes.

Class 1: Engine. (in component interface)

@Provides
public Engine myEngine(Context context) {
    return new Engine (context);
}

Class 5 2: Parts. Engine also needs Parts instance 4 but the creation is delayed.

@Inject
public Parts(Context context, Engine engine) {
    this.context = context;
    this.engine= engine;
    engine.setParts(this);
}

Circular dependency 3 can be achieved but one class must be initiated 2 first before the other.

Again, if possible, refactor 1 code to avoid circular DI.

More Related questions