匕首 - 嵌套注射,是否需要调用inject()?

时间:2015-02-04 19:47:51

标签: android dependency-injection dagger

我是Dagger的新手,在初学期我遇到了一些问题。到目前为止,我的项目结构简单。我的注射模块:

@Module(
    injects = {GameBoardFragment.class, GameManager.class},
    complete = false,
    library = true
)

public class GameObjectsProviderModule {
private final Application mApplication;

public GameObjectsProviderModule(Application application){
    this.mApplication = application;
}

@Provides
@Singleton
public GameManager provideGameManager(){
    return new GameManager();
}

@Provides
public Board getBoard(){
    return new Board();
}

@Provides @Singleton @ForApplication Context provideAppContext() {
    return mApplication;
}

我的简化自定义应用类看起来像这样:

public class MyApp extends Application {
private static ObjectGraph mApplicationGraph;

@Override public void onCreate() {
    super.onCreate();

    mApplicationGraph = ObjectGraph.create(new GameObjectsProviderModule(this));
}

public static ObjectGraph getObjectGraph(){
    return mApplicationGraph;
}
}

现在,我的片段看起来像那样:

public class GameBoardFragment extends Fragment {

@Inject
GameManager mGameManager;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    MyApp.getObjectGraph().inject(this);

    View root = inflater.inflate(R.layout.fragment_game_board, container, false);
    findViews(root);
    confViews();

    return root;
}
}

最后是我的GameManager课程

public class GameManager  {

    @Inject Board mBoard;

    public GameManager(){
        MyApp.getObjectGraph().inject(this);
    }
}

安迪嘿,它有效!大。但我的问题是为什么它不起作用以防我注释掉这一行:

MyApp.getObjectGraph().inject(this);

我们是否总是显式调用inject()函数来使所有必要的注入在嵌套对象中发生? 它看起来并没有,正如coffe制造商的例子所示:

https://github.com/square/dagger/tree/master/examples/simple/src/main/java/coffee

为什么我必须在GameManager类中调用inject()才能使它工作?


编辑:

consturctor注入方法效果很好。

但是为了将来的使用,我试图让野外注射运行,到目前为止我还没有成功。

我从模块中注释了两个@Provide方法,并且我使我的GameManager看起来像这样:

@Singleton
public class GameManager  {

@Inject Board mBoard;

@Inject
  public GameManager(){
}
}

和董事会:

public class Board {

  @Inject
  public Board() {
  }
}

但是mBoard没有实例化。我会尝试更多,我想我找到了正确的解决方案。

2 个答案:

答案 0 :(得分:2)

您应该使用构造函数注入(例如Thermosiphon),并且除非必要,否则请避免使用字段注入。例如,让您的GameManagerBoard作为构造函数参数:

@Singleton
public class GameManager  {

  private final Board mBoard;

  @Inject
  public GameManager(final Board board){
      mBoard = board;
  }
}

Dagger将使用此构造函数创建GameManager的实例(因此为@Inject注释),并注意它需要Board实例。使用ObjectGraph,它将首先创建Board,然后使用该实例创建GameManager。如果你这样做,你可以删除@Provides GameManager方法。

在您的情况下,您的模块中有@Provides Board方法。如果您向@Inject构造函数添加Board注释,则可以从模块中删除此提供方法:

public class Board {

  @Inject
  public Board() {
  }
}

如果你不想使用构造函数注入,问题是你告诉Dagger你想自己创建GameManager实例(因为你有@Provides GameManager方法)。如果你删除这个方法,让Dagger像上面那样为你创建它,但是在构造函数中没有Board参数,Dagger也会注意到@Inject Board字段并注入它。


最后的评论。删除library = truecomplete = false语句!在这个例子中根本不需要这些。如果您真的知道自己在做什么,只能添加它们。如果没有它们,Dagger将创建编译时错误以通知您出现了问题。如果你确实包括它们,那么你告诉Dagger“嘿,我知道我在做什么,不要担心,这一切都是正确的”,而实际上并非如此。


修改

来自Dagger1网站的引用:

  

如果您的班级有@Inject-annotated字段但没有@Inject-annotated   构造函数,Dagger将使用无参数构造函数(如果存在)。   缺少@Inject注释的类不能由Dagger构建。

我不经常使用这种方法,所以我可能错了。我认为这意味着您应该从构造函数中删除@Inject注释,如下所示:

@Singleton
public class GameManager  {

  @Inject Board mBoard;

  public GameManager(){ // Or remove the constructor entirely since it's empty
  }
}

由于@Inject字段上有Board注释,Dagger将知道使用无参数构造函数。

答案 1 :(得分:1)

我正在努力解决同样的问题,因为大多数匕首示例都在使用Module with Provide,我很难找到一个完全没有使用Provide的示例。

我创造了这个。它使用字段注入(不是构造函数注入),并且可以在层次结构中正常工作,而无需任何注入调用。我正在使用Dagger 1.2.2。

Main.java

import javax.inject.*;
import dagger.*;
import dagger.ObjectGraph;

public class Main {

    public static void main(String[] args) {

        ObjectGraph objectGraph = ObjectGraph.create(new CarModule());
        Car car = objectGraph.get(Car.class);
        car.start();
    }
}

CarModule.Java

import dagger.Module;

@Module(injects = Car.class)
public class CarModule {

}

Car.Java

import javax.inject.*;

public class Car {
    @Inject public Engine engine;

    @Inject Car() {
        System.out.println("Car constructor");
    }
    public void start() {
        engine.start();
    }

}

Engine.Java

import javax.inject.*;
public class Engine {
    @Inject WaterPump waterPump;

    Engine() {
        System.out.println("Engine Constructor");
    }
    void start() {
        waterPump.run();
        System.out.println("starting engine.");
    }
}

WaterPump.Java

import javax.inject.*;
public class WaterPump {
    @Inject WaterPump() {
        System.out.println("WaterPump Constructor.");
    }

    public void run() {
        System.out.println("WaterPump running.");
    }
}

输出结果为:

Car constructor
Engine Constructor
WaterPump Constructor.
WaterPump running.
starting engine.

没有声明它的CarModule注入Car.Class这不起作用。你得到:

  

线程中的异常" main" java.lang.IllegalArgumentException:没有   注册成员/汽车注册。您必须明确地将其添加到   '内喷射'其中一个模块中的选项。

但请注意CarModule不会@Provides任何事情。匕首是使用对象图自动创建所有依赖项的。

另请注意,如果班级中有@Inject字段,则不必在默认构造函数上放置@Inject注释。对于Car类,我在构造函数和字段上使用它,在Engine类中,我只将它用于字段而不是构造函数,并且它可以正常工作。