【问题标题】:Understanding Dagger2 subcomponents了解 Dagger2 子组件
【发布时间】:2015-12-31 04:19:46
【问题描述】:

我的应用中有以下 Dagger2 架构:

-- AppComponent (@PerApplication)
  -- UserComponent (@PerUser)
    -- ActivityComponent (@PerActivity)
      -- ChatComponent (@PerActivity) <-- 1

在哪里: 应用组件:

@PerApplication
@Component(modules = {ApplicationModule.class, StorageModule.class, NetworkModule.class})
public interface ApplicationComponent {
    UserComponent plus(UserModule userComponent);

    //Exposed to sub-graphs.
    Context application();
}

用户组件:

@PerUser
@Subcomponent(modules = {UserModule.class, RosterModule.class})
public interface UserComponent {
    ActivityComponent plus(ActivityModule activityModule);

    User getMe();

    UserRepository userRepository();
}

活动组件:

@PerActivity
@Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent {

    ChatComponent plus(ChatModule chatComponent);

    //Exposed to sub-graphs.
    Context context();
}

聊天组件:

@PerActivity
@Subcomponent(modules = {ChatModule.class})
public interface ChatComponent {
    void inject(ChatListFragment chatListFragment);
    void inject(ConversationFragment conversationFragment);
    void inject(NewConversationFragment newConversationFragment);
    void inject(CloudFilesFragment cloudFilesFragment);
    void inject(ChatActivity chatActivity);
    void inject(ConversationActivity conversationActivity);
    void inject(NewConversationActivity newConversationActivity);

    void inject(NewGroupActivity newGroupActivity);
    void inject(NewGroupFragment newGroupFragment);
}

我面临两个问题:

首先,如何将不同的Context 注入到我的课程中?应用或活动??

其次,我在尝试编译代码时遇到了一个奇怪的问题,错误是:

错误:(23, 10) 错误: br.com.animaeducacao.ulife.domain.interactor.UseCase 不能 在没有 @Provides 注释的方法的情况下提供。 br.com.animaeducacao.ulife.presentation.view.fragment.ChatListFragment.chatListPresenter [类型的注入字段: br.com.animaeducacao.ulife.presentation.presenter.ChatListPresenter 聊天列表演示者] br.com.animaeducacao.ulife.presentation.presenter.ChatListPresenter.(br.com.animaeducacao.ulife.domain.interactor.UseCase 聊天对话用例, br.com.animaeducacao.ulife.domain.interactor.UseCase adviceUserPresence,android.content.Context 上下文)[参数: @javax.inject.Named("getChatDialogs") br.com.animaeducacao.ulife.domain.interactor.UseCase chatDialogsUseCase]

我的 ChatListFragment 是:

@PerActivity
public class ChatListFragment extends BaseFragment implements ChatListView {

    @Inject
    ChatListPresenter chatListPresenter;
  ...
//called onActivityCreated()
private void initialize() {
        this.getComponent(ChatComponent.class).inject(this);
}

基本片段:

protected <C> C getComponent(Class<C> componentType) {
    return componentType.cast(((HasComponent<C>)getActivity()).getComponent());
  }

ChatListPresenter:

@PerActivity
public class ChatListPresenter implements Presenter {

    private final UseCase chatDialogsUseCase;
    private final UseCase adviceUserPresence;
    private final Context context;
    private ChatListView chatListView;

    @Inject
    public ChatListPresenter(@Named("getChatDialogs") UseCase chatDialogsUseCase,
                             @Named("adviceUserPresence") UseCase adviceUserPresence,
                             Context context) {
        this.chatDialogsUseCase = chatDialogsUseCase;
        this.adviceUserPresence = adviceUserPresence;
        this.context = context;
    }

问题是,在我的 ChatModule 类中,我已经实现了所有必要的 @Provides

@Provides
    @PerActivity
    @Named("getChatDialogs")
    public UseCase provideChatDialogs(@Named("transactionalChatRepository") ChatRepository chatRepository, ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
        return new GetUserChatDialogs(chatRepository, threadExecutor, postExecutionThread);
    }

这是一个好方法吗?为什么这不编译,我在这里缺少什么? 抱歉发了这么长的帖子,谢谢!

【问题讨论】:

  • 请阅读更多关于匕首的教程。您得到的错误可能是因为您只提供了一个命名用例。另外,你不应该关心context。如果你需要activity,注入activity,如果你需要上下文,你可能应该去app context

标签: java android dagger-2


【解决方案1】:

啊,你有很多问题。

1.) 当您正确地使用子范围时(您正在首先正确地制作 @Subcomponents),ChatComponent 实际上并没有对其父组件进行子范围 -基本上,ChatComponent 不能是@PerActivity,它需要是第四个作用域。

@Subcomponent 注解只是一种创建子作用域组件的方法,而无需将其指定为组件依赖项。它仍然需要自己的“更具体”的范围。

2.) 要使子作用域起作用,您需要在组件中为该组件要提供的每个依赖项指定提供方法,以便子作用域的组件可以继承它们。

例如,您的ApplicationComponent 没有针对StorageModule 中的内容的提供方法,因此StorageModule 提供的依赖项不能被继承到子作用域组件。

但是,我不确定您是否可以仅指定您提供的类(如果它不在模块内),而是使用 @Inject 构造函数进行注释,并且该类标有范围。

另外,为了在作用域层次结构A-&gt;B-&gt;C 中允许 C 从 A 继承,那么 B 也需要具有 A 的提供方法。

所以UserComponent extends ApplicationComponent 是必要的,ActivityComponent extends UserComponentChatComponent extends ActivityComponent

3.) 您应该使用@Named("application")@Named("activity") 注释来指定两个不同的Context,或者只是在您的模块中将它们称为ApplicationActivity,这样它们就不会得到搞混了。

【讨论】:

  • 引用 Dagger2 Javadoc:“从父 {@link Component} 或 * {@link Subcomponent} 继承绑定的子组件”。我不明白为什么我应该使用@Subcomponent 扩展任何接口。我试过了,构建时出现 Stackoverflow 错误。感谢您到目前为止的回答和解释!
  • 从技术上讲,我知道组件依赖项需要它,但我不确定子组件是否也需要它。您是否更改了聊天组件的范围?
  • 在这种情况下,你需要发布你的模块代码......但我认为如果你为每个用例都有类,这样你就不必在它们上使用@Named,这会有所帮助,你可能会忘记其中之一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-17
相关资源
最近更新 更多