我是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没有实例化。我会尝试更多,我想我找到了正确的解决方案。
答案 0 :(得分:2)
您应该使用构造函数注入(例如Thermosiphon),并且除非必要,否则请避免使用字段注入。例如,让您的GameManager
将Board
作为构造函数参数:
@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 = true
和complete = 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
类中,我只将它用于字段而不是构造函数,并且它可以正常工作。