読者です 読者をやめる 読者になる 読者になる

daggerサンプルコードの最初から、メソッドなどの関係が分からなかったので、理解しようと頑張った

なんとなく勉強会などで説明を聞いていて
DIとかよりまず処理の流れがよく分かっていませんでした。。

@Moduleのついているクラス@Providesがついているメソッドを使うと@Injectのところに入れてくれるとかは聞いていた

public class MainActivity extends Activity{
    @Inject Test test;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        ObjectGraph.create(new TestModule()).inject(this);
    }
}
@Module(injects = MainActivity.class)
public class TestModule {
    @Provides
    Test provideTest() {
        return new Test();
    }
}

こんなイメージだった

これだとMainActivity.testに入れる変数をTestModuleから提供される感じだった

そんな感じで公式のdaggerのサンプルを読もうとした

square/dagger · GitHub

サンプルコードの最初はこういう感じ

public class CoffeeApp implements Runnable {
  @Inject CoffeeMaker coffeeMaker;

  @Override public void run() {
    coffeeMaker.brew();
  }

  public static void main(String[] args) {
    ObjectGraph objectGraph = ObjectGraph.create(new DripCoffeeModule());
    CoffeeApp coffeeApp = objectGraph.get(CoffeeApp.class);
    coffeeApp.run();
  }
}

このmainを実行する
CoffeeMakerはこうなっている

class CoffeeMaker {
  @Inject Lazy<Heater> heater; // Don't want to create a possibly costly heater until we need it.
  @Inject Pump pump;

  public void brew() {
    heater.get().on();
    pump.pump();
    System.out.println(" [_]P coffee! [_]P ");
    heater.get().off();
  }
}

普通に考えるのがDripCoffeeModuleの中に、CoffeeApp.coffeeMakerに変数を入れる@Providesが書いてあるとか思うでしょう?

でも

@Module(
    injects = CoffeeApp.class,
    includes = PumpModule.class
)
public class DripCoffeeModule {
  @Provides @Singleton Heater provideHeater() {
    return new ElectricHeater();
  }
}

Heaterなどは提供してくれる処理があるけど、 PumpModuleなどをたどっていってもCoffeeMakerを提供してくれる処理はないです

daggerはInjectって書いてあるところのクラスを勝手にnewして入れてくれるっぽいです。
つまりdaggerはobjectGraph.getや@Providesが付いているメソッドの引数などでオブジェクトが必要になったタイミングで以下のように動くみたいです  

if @Moduleが付いているクラス and @Providerの付いている返り値がCoffeeAppのメソッドがある:    
  それを使って作る  
else if  CoffeeAppに@Injectが付いているコンストラクタがある:  
  それを使って作る  
else :
  new CoffeeApp();#(CoffeeAppのクラスの中には@Injectがついているメンバ変数を含んで、injects=CoffeeApp.classのModuleが必要)  

こんなイメージです

サンプルコード

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        ObjectGraph.create(new TestModule()).get(Test.class).hello();
    }
}

@Module(injects = Test.class)
public class TestModule {
    @Provides
    public SayHello provideSayHello() {
        return new SayHello();
    }
}

public class Test {
    public Test(){
        System.out.println("Test created");
    }
    @Inject
    SayHello sayHello;
    public void hello(){
        sayHello.hello();
    }
}

public class SayHello {
  void hello(){
      System.out.println("hello");
  }
}
Test created
hello

間違いなどがありましたらご指摘ください