如何正确使用Dagger 2的LibGDX现场注射?

时间:2016-03-09 23:10:04

标签: java android dependency-injection libgdx dagger-2

我在基于LibGDX的游戏中注入一些依赖项时遇到问题。 谁能指出我缺少的东西?

我有两个模块。

首先提供Android' Context

@Module
public class AppModule {
    Context context;

    public AppModule(Context context) {
        this.context = context;
    }

    @Provides
    @Singleton
    Context providesContext() {
        return context;
    }
} 

第二个提供与Google Analytics互动的课程:

@Module
public class ServicesModule {
    @Provides
    @Singleton
    AnalyticsUtils providesAnalyticsUtils(Context context) {
        return new AnalyticsUtils(context);
    }
}

我的组件类以这种方式实现:

@Singleton
@Component(modules = {AppModule.class, ServicesModule.class})
public interface GameComponent {
    void inject(Launcher launcher);
}

现在,我已经添加了自定义Application类(在manifest中定义),我在其中实例化了我的组件:

public class GameApplication extends Application {
    private GameComponent gameComponent;

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

        gameComponent = DaggerGameComponent.builder()
            .appModule(new AppModule(this))
            .servicesModule(new ServicesModule())
            .build();
    }

    public GameComponent getGameComponent() {
        return gameComponent;
    }
}

在LibGDX And​​roid的启动器中,我在onCreate方法中调用了组件的inject()方法:

public class Launcher extends AndroidApplication {

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

        ((GameApplication) getApplication()).getGameComponent().inject(this);

        initialize(new GameName());
    }
}

让我们说GameName是一个扩展LibGDX Game类的类。在其create方法中,我调用setScreen方法启动菜单屏幕。

我的MenuScreen课程:

public class MenuScreen extends ScreenAdapter {
    @Inject AnalyticsUtils analyticsUtils;

    public MenuScreen(GameName game) {
        // Some initialization.
        useAnalytics();
    }

    private void useAnalytics() {
        analyticsUtils.someMethod();
    }
}

如上所述,在MenuScreen类中,我想使用字段注入注入AnalyticsUtils类。

在构造函数中,我调用的方法是使用analyticsUtils对象并调用它的方法。

在我正在调用的analyticsUtils.someMethod()行,我正在NullPointerExcetion(试图在.someMethod()对象上调用null)。

我是否应该在每个注入任何东西的类中使用组件的inject()方法(无论使用字段/构造函数注入)?

我已阅读了很多Dagger的教程和文档,但每个可用的示例都很简单(大多数情况下,它们在活动中显示简单的注入)。

经过几个小时的尝试后,我决定要问一位在匕首方面经验丰富的人。我会很高兴任何提示和/或资源。

1 个答案:

答案 0 :(得分:2)

注释本身不会做任何事情 - MenuScreen没有提供它的依赖。

只要有可能就使用构造函数注入。

字段注入将由活动和片段使用,因为您无法修改/使用它们的构造函数。除了一些罕见的情况,你应该尽可能使用构造函数注入。

public class MenuScreen extends ScreenAdapter {
    private final AnalyticsUtils analyticsUtils;

    @Inject 
    public MenuScreen(GameName game, AnalyticsUtils analyticsUtils) {
        this.analyticsUtils = analyticsUtils;
        // Some initialization.
        useAnalytics();
    }

    private void useAnalytics() {
        analyticsUtils.someMethod();
    }
}

如果可以提供所有依赖项,这将有效。

使用匕首意味着您自己调用构造函数

((GameApplication) getApplication()).getGameComponent().inject(this);

initialize(new GameName());

GameName 显然应该从GameComponent提供

如果您可以提供课程,请不要使用模块

@Provides
@Singleton
AnalyticsUtils providesAnalyticsUtils(Context context) {
    return new AnalyticsUtils(context);
}

你不需要这些。使用class AnalyticsUtils注释@Singleton,使用@Inject注释其构造函数,然后可以提供。 没有任何模块。这就是构造函数注入的原因。

使用注入

您没有提供有关您在哪里做什么的背景信息。但鉴于可以提供GameName,可以构建MenuScreen。你可以,例如只需执行以下操作

@Inject
GameName mGame;
@Inject
MenuScreen mMenu;

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

    ((GameApplication) getApplication()).getGameComponent().inject(this);

    initialize(mGame);
}