【问题标题】:Calling inject() from a Dagger Module method - bad practice?从 Dagger Module 方法调用 inject() - 不好的做法?
【发布时间】:2014-12-12 10:38:40
【问题描述】:

我还是依赖注入的新手,我尝试使用 MVP 设计模式来实现我的应用程序。我为每个视图使用范围图。在阅读完this great article 之后,我决定将我的适配器视为视图的一部分。

我的示例中的视图是一个片段。我创建了一个模块 [称为 FragmentModule],它提供了它的 PresenterView

在我开始捣乱之前,该模块只注入了 Fragment,并通过调用其构造函数并使用所需参数提供了 FragmentAdapter

模块:

@Module(
        overrides = true,
        includes = BaseFragmentModule.class,
        injects = {
                MyFragment.class,
        }
)
public class FragmentModule {

    private MyFragment mFragment;

    // ... // Other methods removed for clarity

    @Provides
    @Singleton
    public FragmentAdapter provideAdapter() {
        return new FragmentAdapter(mFragment.getActivity(), mFragment);
    }

    // ... //
}

FragmentAdapter 构造函数看起来有点像这样:

private Context mContext;
private CustomListener mListener;

public FragmentAdapter(Context context, CustomListener listener)
{
    mContext = context;
    mListener = listener;
    // ... // 
}

这可能仍然是“正确的做法”,但我想讨论一下我目前的做法,所以请继续阅读!

然后我再次重写它,以便 FragmentAdapter 引用 Fragment 实例。然后我在 FragmentAdapter 构造函数中分配了 Context 和 Listener。

private MyFragment mFragment;

@Provides
@Singleton
public FragmentAdapter provideAdapter() {
    return new FragmentAdapter(mFragment);
}

适配器构造函数如下所示:

private Context mContext;
private CustomListener mListener;

public FragmentAdapter(MyFragment iFragment)
{
    mContext = iFragment.getActivity();
    mListener = iFragment;
    // ... // 
}

在那之后,我决定出于某种原因将上下文注入适配器。所以我继续说: 我让 FragmentModule 也注入了适配器,如下所示:

@Module(
        overrides = true,
        includes = BaseFragmentModule.class,
        injects = {
                FragmentAdapter.class,
                MyFragment.class,
        }
)

现在我必须学习如何以一种简洁明了的方式将 FragmentAdapter 注入 Fragment 的作用域 ObjectGraph。首先,我从 FragmentAdapter 构造函数中调用了 inject()

片段模块:

// ... //
private MyFragment mFragment;
// ... //
@Provides
@Singleton
public FragmentAdapter provideAdapter() {
    return new FragmentAdapter(mFragment);
}
// ... //

片段适配器

@Inject Context mContext;
@Inject MyListener mListener;

public FragmentAdapter(MyFragment iFragment)
{
    iFragment.getObjectGraph().inject(this);
    // ... // 
}

再次,出于某种原因(记住我正在学习..) - 我想让注入工作而不必将 Fragment 实例传递给 FragmentAdapter 构造函数,所以我最终从 Module 类中调用 inject()

    @Provides
    @Singleton
    public FragmentAdapter provideAdapter() {
        if (mAdapter == null) {
            mAdapter = new FragmentAdapter();
            mFragment.getObjectGraph().inject(mAdapter);
            mAdapter.initialize(); // Code moved from constructor which depends on injected members
        }
        return mAdapter;
    }

现在我很好奇 - 您认为这里的最佳做法是什么?您将如何使用 Dagger 注入实现适配器和片段依赖项?为什么?

非常感谢您的反馈!

【问题讨论】:

    标签: android mvp dagger


    【解决方案1】:

    在我看来,ObjectGraph.inject(...) 应该尽量避免。相反,您想要进行构造函数注入:在构造函数中传递注入的依赖项。

    您可以通过在构造函数中添加 @Inject 注释来做到这一点:

    private final Context mContext;
    private final MyListener mListener;
    
    @Inject
    public FragmentAdapter(Context context, MyListener listener)
    {
        mContext = context;
        mListener = listener;
        // ... // 
    }
    

    现在,您不再需要 provideAdapter(),因为 Dagger 可以识别构造函数上的 @Inject 注释。您确实需要提供 ContextMyListener 实例,我相信您已经在这样做了。

    话虽如此,我不认为应该注入MyListener。它不是您的FragmentAdapter 的依赖项,而是一项功能。只需从您的 Fragment 班级中致电 setListener(MyListener)

    最后一句话,有时inject(...) 是不可避免的。尤其是当您使用其构造函数不受您管理的类时(例如 ActivityFragment)。

    【讨论】:

    • 感谢您的意见尼克!我已经解决了构造函数注入。我同意你的评论——事实上我最终删除了以前使用的接口,并直接在适配器中处理事件——因为无论如何我认为它是视图的一部分。对或错.. 这是一个可扩展的列表视图。
    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 2020-07-26
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多