【问题标题】:Dagger 2 Inject Child ClassDagger 2 注入子类
【发布时间】:2016-02-23 16:24:03
【问题描述】:

我知道,对于 Dagger 2,我无法注入基类并期望它能够延续到子类。但是为什么我不能在子类中调用注入,除非我明确地为该类提供了inject 方法?

我尝试按照本文中的示例进行操作:Dagger 2: Even Sharper, Less Square。这个解决方案应该允许我在子类中调用注入,但是当我测试它时,我会为我的所有 @Inject 目标获得一个 NullPointerException

public abstract class BaseFragment extends Fragment {

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

    protected abstract void injectComponent(AppComponent component);
}

public class MyFragment extends BaseFragment {

    @Inject MyDependency mDependency;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
        mDependency.doSomething(); // NullPointerException
        ...
    }

    ...

    @Override
    public void injectComponent(AppComponent component) {
        component.inject(this);
    }
}

是否有另一种方法可以注入每个子类而不为每个类创建注入方法?或者这是 Dagger 2 唯一可行的方法?如果是这样的话,我最终会得到一个荒谬的长 Component 类。为每个 ActivityFragment 或各种其他帮助类使用注入方法:

@Singleton @Component(modules = {AppModule.class})
public interface AppComponent {

    void inject(MyClass clazz);

    void inject(MyClass2 clazz);

    ...

    void inject(MyClassN clazz);
}

我宁愿在每个班级都调用component.inject(),也不愿与另一个inject 方法一起调用。


虽然相似,但我不认为我的问题与Dagger 2 Activity Injection Not Working 重复。该问题询问为什么注入不起作用,答案是:因为 Dagger 2 具有强大的类型关联,您必须为每个类声明一个 inject 方法。这个问题更侧重于绕过样板的方法,同时希望保持强类型关联。

【问题讨论】:

  • 据我了解 Dagger2,您的假设是正确的,即它仅适用于您想要注入值的每个类的注入方法。据我所知,建议的解决方案是创建许多范围组件,以提供该特定活动/片段或应用程序的一部分所需的东西。希望对您有所帮助
  • @MikaelOhlson 考虑到我目前有大约 30 个片段,其中大部分依赖于 Retrofit 客户端,这令人沮丧。更不用说任何类可能需要的所有其他依赖项。
  • 您的@Inject 注释字段需要存在于基类中,子类中的任何内容都不会被看到(我相信这是由于反射被用于匕首类生成)。你总是可以让你的组件使用临时方法而不是注入方法,比如 appComponent.getMyDependency()。您可以将实际组件本身作为受保护的变量注入基类,并在子类中的组件上使用临时方法。这些只是我能想到的几个选项。
  • @ootinii 是的,我发现了,很遗憾。至于临时方法,我也知道,但这是我想避免的很多样板。

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


【解决方案1】:

我发现了一个漂亮的小技巧,用在AsymmetricFingerprintDialog 示例应用程序中,虽然我不知道我是否完全理解它是如何工作的。该示例使用 Dagger 的第一次迭代,但快速测试表明它也适用于 Dagger 2。

对于每个Fragment,我添加了一个带有@Inject 注释的空构造函数,然后使用@Inject 注释在我的Activity 中获取Fragment 的实例。

public class MainActivity extends AppCompatActivity {

    @Inject MyFragment mFragment;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyApplication.getComponent().inject(this);
        getSupportFragmentManager().beginTransaction
                .replace(R.id.fragment_container, mFragment).commit();
        ...
    }
}

public class MyFragment extends Fragment {

    @Inject MyDependency mDependency;

    @Inject
    public MyFragment() {}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
        mDependency.doSomething();
        ...
    }
}

这允许我只在每个Activity 中调用MyApplication.getComponent().inject(this),并且依赖项也将被注入到Fragment 类中。这样,我只需要为每个Activity 一个inject 方法,而不是每个Fragment

@Singleton @Component(modules = {AppModule.class})
public interface AppComponent {

    void inject(MainActivity activity);
}

我很好奇这是如何工作的。据我所知,它与 Dagger 无关,而是似乎将 @Inject 注释用于其预期目的?虽然我是 Dagger 和 JSR-330 的新手,但我不确定。


编辑:此方法仅适用于setRetainInstanceState(true),或者如果您自己保存和恢复实例。

【讨论】:

  • 要小心,因为 Fragments 可以由 Android 自己创建。所以在这种情况下不会发生注入
  • @EugenMartynov 啊,我没想到。你是对的,NullPointerException 改变方向。我认为Fragment 在重新创建时会被Activity 重新创建,我想事实并非如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-21
  • 2022-09-30
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多