【问题标题】:Null object for @Inject field@Inject 字段的空对象
【发布时间】:2015-03-18 22:11:33
【问题描述】:

我正在为我的 Android 应用程序遵循 MVC 模式,并且遇到过几次这个问题并且不得不解决它。 当我的应用程序能够使用字段上的 @Inject 注释创建注入对象时,该对象的 @Inject 字段为空,通常会导致崩溃。例如,我有处理逻辑的控制器类和流动。任何片段/活动都会回调到它们的控制器以通知用户交互/状态更改。但是,注入的Controller实例通常为null。

我将举一个简单的例子来说明。下面,控制器创建了一个注入的活动,然后通过添加一个片段来使用它来启动流程。处理了该依赖关系,但未处理对控制器的活动依赖关系(即 null)。

处理业务逻辑和流程的简单控制器类:

public class SomeController {
    @Inject
    SomeActivity someActivity;

    private SomeComponent component;

    private final Application app;

    @Inject
    public SomeController(Application app) {
        this.app = app;
    }

    private void startActivity() {
        component = Dagger_SomeComponent().builder()
             .someModule(app)
             .build();

        someActivity.getFragmentManager().beginTransaction().
            .add(R.id.content, SomeFragment.class, null)
            .commit();
    }

    public void activityStarted() {
        //callback when Activity is ready...
    }
}

处理用户交互并回调控制器以执行一些业务逻辑的简单活动:

public class SomeActivity extends Activity {

    @Inject
    SomeController controller;

    private void controllerCallback() {
          //notify controller of something here...
    }
}

用于将对象注入图形的简单模块类:

@Module
public class SomeModule {

    private Application app;

    public SomeModule(Application app) {
         this.app = app;
    }

    @Provides
    @Singleton
    SomeController provideSomeController( return new SomeController(app); )

    @Provides
    SomeActivity provideSomeActivity( return new SomeActivity();)
}

提供消费对象方法的简单组件类:

@Component
public interface SomeComponent {

    void addController(SomeController controller);

    SomeController controller();

    SomeActivity activity();
}

【问题讨论】:

  • 你初始化组件吗?你在哪里注入这个对象? Dagger-2 没有使用反射机制
  • 对,应该添加。将其编辑。试图将其精简为基本要素,以便更容易讨论我一直在解决这个问题的原因/原因/方式。假设应用程序在想要启动该功能时在控制器上调用 startActivity()。
  • 也忘记将 Activity 添加到模块。这就是我从记忆中得到的。所以,我的理解是,Module 会为 SomeActivity 提供任何可注入字段,这似乎发生在 Controller 中,但是为什么 Activity 的 Controller 的可注入字段 == null?
  • 什么是一些Activity是扩展Activity的对象
  • 我的意思是 SomeActivity 类

标签: java android dependency-injection dagger-2


【解决方案1】:

我相信您的示例中遗漏了一些内容:

1) Dagger2 组件是一些提供依赖的模块和一些“消耗”依赖的注入点之间的桥梁。您的组件应至少有一个链接模块,并且注释应如下所示:

@Component(modules = SomeModule.class)

2) 在模块中使用“new”操作符进行 SomeActivity 实例化是没有意义的。好的,你可以创建 Activity 对象,但是谁来管理它的状态,调用它的生命周期方法等呢?如果您真的想将现有 Activity 的引用作为依赖项传递 - 这是可能的,但方式不同。例如,创建应用程序级模块和组件,以及单独的活动级模块和组件,将现有的活动引用作为模块构造函数参数传递。

3) Activity 是由 Android 框架创建的,因此您应该在 Activity 中使用字段注入。在您的组件中添加如下行:

void inject(SomeActivity activity);

并将创建组件的代码放入Activity。例如 onCreate():

SomeComponent component = Dagger_SomeComponent().builder()
         .someModule(getApplication())
         .build()
         .inject(this);

4) 请尽量避免在开头使用@Singleton 注解。首先确保您声明的所有依赖项都得到满足并且您不再有空值。接下来您可以检查一些现有的 Dagger2 开源项目以进行正确的范围注释。

【讨论】:

  • 1.是的,你是对的,我不小心把它漏掉了。我不打算将其作为具体实现,更像是伪代码来说明问题。也就是说,为什么注入的对象 @Inject 字段会为空? 2. 同意,实际上我不会在活动中使用注入。 3.这打破了MVC模型,将组件创建交给Activity而不是Controller,imo。 4. 不确定您在此声明中的目标是什么?单例是有用的模式。
  • 3.您可以选择在哪里创建对象图(组件)。但是 Activity 是基本块,没有 Activity 就无法创建屏幕、对话框等。因此,您可以在控制器中创建对象图,但您还必须使用 new 运算符直接在活动中创建控制器实例。因此,IMO 最好从 MVC 纯度退一步,在活动中创建组件并使用该组件将依赖项注入活动。 4. 你可能在使用范围时遇到了一些问题,所以我建议在第一步解决空值的问题,然后请在你想要的地方使用单例注释。
  • 在一个应用程序中,我使用默认的“启动屏幕”活动来启动应用程序,因为 Android 需要它作为入口点。 Application 类可以通过为功能模块启动控制器来替换此 Activity 和控制流。控制器使用意图创建活动,并回调控制器。我觉得这相当漂亮和干净。我遇到的问题是当我有一个带有@Inject 构造函数的A 类时-> 控制器创建了一个B 类的实例,该实例依赖于A-> B 对象的A 的@Inject 字段为空。我确定我错过了一些东西。 ://
  • 好的,如果我清楚地理解了您的最后一条评论,仅在 B 类中用 @Inject A a 注释一个依赖项是不够的。如果您(您的控制器)显式实例化 B 类,则需要 1)选择谁将注入依赖项 - 控制器或 B 类构造函数; 2)在控制器或B构造函数中有一个构建的对象图(组件); 3) 使用在组件方法中声明的方式进行注入,如 void injection(B b);
  • 是的,我们知道了。如果你把它放在答案中,我会标记它。感谢您的帮助!
【解决方案2】:

我遇到了这个问题,并使用this accepted answer 解决了它。

TLDR:我必须在组件中添加 inject() 方法才能准确 类型,而不仅仅是inject(SomeSuperclass foo)

基本上,我有一个需要注入的 Activity:

class SubActivity extends BaseActivity {
    @Inject Type someVar;

    @Override
    protected void onCreate(Bundle bundle) {
       getComponent().inject(this);
    }
}

但我的组件看起来像:

@Component
public interface MyComponent {
    void inject(BaseActivity activity); // This allows SubActivity to compile but messes up injection
}

解决方案:为确切的子类型添加注入方法:

@Component
public interface MyComponent {
    void inject(BaseActivity activity);
    void inject(SubActivity activity); //<-- This solved it
}

【讨论】:

【解决方案3】:

在我的情况下,depends-on="bean1" 在应用程序上下文中的属性占位符内导致了问题。我使用@PostConstruct 进行注入工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-28
    • 2015-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    相关资源
    最近更新 更多