【问题标题】:How to correctly use Dagger 2's field injection with LibGDX?如何在 LibGDX 中正确使用 Dagger 2 的场注入?
【发布时间】:2016-03-09 23:10:04
【问题描述】:

我在基于 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);
}

现在,我添加了自定义应用程序类(在清单中定义),并在其中实例化了我的组件:

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(试图在null 对象上呼叫.someMethod())。

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

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

经过几个小时的尝试,我决定我需要请教在 Dagger 方面更有经验的人。我会很高兴任何提示和/或资源。

【问题讨论】:

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


    【解决方案1】:

    注解本身不会做任何事情——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();
        }
    }
    

    如果可以提供所有依赖项,这将起作用。

    使用 dagger 意味着你不应该自己调用构造函数

    ((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);
    }
    

    【讨论】:

    • 事实上,我的MenuScreen 类(和许多其他类)使用了我想注入的更多依赖项。我想我应该创建带有多个参数的如此糟糕的构造函数还是创建包含其他对象的包装类?这就是我想使用字段注入的原因。
    • @tommus 我认为“包含其他对象的包装器类”也是一种反模式。如果您对单个类有太多依赖项,这可能意味着它做得太多。然后你应该将它的一些特征提取到其他类中
    • 是的,我在发表评论后不久就考虑到了这一点。此外 - 感谢您的回复。我将您的答案标记为正确。它阐明了这个主题并改变了我对 Dagger 的看法和理解(尤其是依赖于缺少使用模块的要求的快捷方式)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-31
    • 1970-01-01
    • 2022-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多