了解Dagger2子组件

时间:2015-12-31 04:19:46

标签: java android dagger-2

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

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

其中: AppComponent:

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

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

UserComponent:

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

    User getMe();

    UserRepository userRepository();
}

ActivityComponent:

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

    ChatComponent plus(ChatModule chatComponent);

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

ChatComponent:

@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? App或Activity ??

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

  

错误:(23,10)错误:   br.com.animaeducacao.ulife.domain.interactor.UseCase不能   提供没有@ Provide-annotated方法。   br.com.animaeducacao.ulife.presentation.view.fragment.ChatListFragment.chatListPresenter   [注入类型的字段:   br.com.animaeducacao.ulife.presentation.presenter.ChatListPresenter   chatListPresenter]   br.com.animaeducacao.ulife.presentation.presenter.ChatListPresenter。(br.com.animaeducacao.ulife.domain.interactor.UseCase   chatDialogsUseCase,   br.com.animaeducacao.ulife.domain.interactor.UseCase   adviceUserPresence,android.content.Context context)[参数:   @ javax.inject.Named(&#34; getChatDialogs&#34)   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);
}

BaseFragment:

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

这是一个好方法吗?为什么这不是编译,我在这里缺少什么? 对不起,发帖很长,谢谢!

1 个答案:

答案 0 :(得分:2)

啊,你有很多问题。

1。)当您正确使用子信号到某一点时( 首先使@Subcomponent正确),ChatComponent实际上并不是它的父组件 - 基本上,ChatComponent不能是@PerActivity,它必须是第四个范围。

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

2。)要使subscoping工作,您需要在组件中为该组件要提供的每个依赖项指定provision方法,以便子范围组件可以继承它们。

例如,您的ApplicationComponent没有StorageModule中的内容的提供方法,因此StorageModule提供的依赖项无法继承到子范围组件。

但是我不确定你是否可以只指定你提供的类,如果它不在模块中,而是用@Inject构造函数注释,并且该类用范围标记。

另外,要允许C的范围层次结构A->B->C从A继承,那么B也需要具有A的提供方法。

因此UserComponent extends ApplicationComponent是必要的,ActivityComponent extends UserComponentChatComponent extends ActivityComponent

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