简体   繁体   English

了解Dagger2子组件

[英]Understanding Dagger2 subcomponents

I have the following Dagger2 Architecture in my app: 我的应用程序中包含以下Dagger2体系结构:

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

Where: AppComponent: 其中:AppComponent:

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

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

UserComponent: UserComponent:

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

    User getMe();

    UserRepository userRepository();
}

ActivityComponent: ActivityComponent:

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

    ChatComponent plus(ChatModule chatComponent);

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

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

I'm facing 2 problems: 我面临2个问题:

First, how can I inject different Context to my classes ? 首先,如何为课程注入不同的Context Either App or Activity ?? 应用程序或活动?

And secondly, I'm facing a bizarre issue when trying to compile my code, the error is: 其次,在尝试编译我的代码时,我面临一个奇怪的问题,错误是:

Error:(23, 10) error: br.com.animaeducacao.ulife.domain.interactor.UseCase cannot be provided without an @Provides-annotated method. 错误:(23,10)错误:如果没有@Provides注释的方法,则无法提供br.com.animaeducacao.ulife.domain.interactor.UseCase。 br.com.animaeducacao.ulife.presentation.view.fragment.ChatListFragment.chatListPresenter [injected field of type: 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) [parameter: @javax.inject.Named("getChatDialogs") br.com.animaeducacao.ulife.domain.interactor.UseCase chatDialogsUseCase] 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 advisorUserPresence,android.content.Context context)[参数:@ javax.inject.Named( “ getChatDialogs”)br.com.animaeducacao.ulife.domain.interactor.UseCase chatDialogsUseCase]

My ChatListFragment is: 我的ChatListFragment是:

@PerActivity
public class ChatListFragment extends BaseFragment implements ChatListView {

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

BaseFragment: BaseFragment:

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

ChatListPresenter: 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;
    }

The problem is, in my ChatModule class I have implemented all the @Provides necessary: 问题是,在我的ChatModule类中,我实现了所有必需的@Provides

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

Is this a good approach ? 这是一个好方法吗? Why is this not compiling, what I am missing here ? 为什么这里不编译,我在这里缺少什么? Sorry for the long post and thanks ! 对不起,很长的帖子,谢谢!

Ah, you have multiple problems. 嗯,您有多个问题。

1.) While you're using the subscoping correctly to a point (you are making @Subcomponent s properly at first), the ChatComponent doesn't actually subscope its parent component - basically, ChatComponent cannot be @PerActivity , it needs to be a fourth scope. 1)当你使用正确的subscoping到一个点(你正在 @Subcomponent s请正确地在第一),该ChatComponent实际上并不子范围其父组件-基本上, ChatComponent不能@PerActivity ,它需要一个第四范围。

@Subcomponent annotation is just a way to create a subscoped component without having to specify it as a component dependency. @Subcomponent批注只是一种创建子范围内的组件的方法,而不必将其指定为组件依赖项。 It still needs its own "more specific" scope. 它仍然需要自己的“更具体”的范围。

2.) to make subscoping work, you need to specify provision methods in your component for every dependency that that component is meant to provide, so that the subscoped components can inherit them. 2.)为了使范围化工作有效,您需要在组件中为该组件要提供的每个依赖项指定配置方法,以便子范围内的组件可以继承它们。

For example, your ApplicationComponent doesn't have provision methods for what is in StorageModule , and therefore the dependencies provided by StorageModule cannot be inherited to subscoped components. 例如,您的ApplicationComponent没有提供StorageModule内容的配置方法,因此StorageModule提供的依赖项不能继承到子范围内的组件。

I however am not sure if you can just specify the class you're providing if it is not inside a module, and instead it is annotated with @Inject constructor and the class is marked with the scope. 但是,我不确定如果不是在模块内部,是否可以仅指定要提供的类,而是使用@Inject构造函数对其进行注释,并用范围标记该类。

Also, to allow in a scope hierarchy A->B->C for C to inherit from A, then B needs to have the provision methods of A as well. 而且,为了允许作用域层次结构A->B->C中的C从A继承,那么B也需要具有A的提供方法。

So UserComponent extends ApplicationComponent is necessary, and ActivityComponent extends UserComponent , and ChatComponent extends ActivityComponent . 因此, UserComponent extends ApplicationComponent是必要的,而ActivityComponent extends UserComponent ,而ChatComponent extends ActivityComponent

3.) You should use the @Named("application") and @Named("activity") annotations to specify two different Context , or instead just refer to them as Application and Activity in your module so that they don't get mixed up. 3.)您应该使用@Named("application")@Named("activity")批注指定两个不同的Context ,或者仅在模块中将它们称为ApplicationActivity ,以免混淆起来。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM