java 使用 Dagger 2 进行演示者注入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36838898/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 01:54:19  来源:igfitidea点击:

Presenter injection with Dagger 2

javaandroiddependency-injectionmvpdagger-2

提问by user1341300

I just started using Dagger 2 and I found online thousands guides each one with a different implementation and I'm a bit confused now. So basically this is what I wrote at the moment:

我刚开始使用 Dagger 2,我在网上找到了数千个指南,每个指南都有不同的实现,现在我有点困惑。所以基本上这就是我现在写的:

AppModule.java:

AppModule.java:

@Module
public class AppModule {

 Application mApplication;

 public AppModule(Application application) {
    mApplication = application;
 }

 @Provides
 @Singleton
 Application providesApplication() {
    return mApplication;
 }
}

DataModule.java:

数据模块.java:

@Module
public class DataModule {

private static final String BASE_URL = "http://beta.fridgewizard.com:9001/api/";

@Provides
@Singleton
NetworkService provideNetworkService() {
    return new NetworkService(BASE_URL);
}

@Provides
@Singleton
SharedPreferences provideSharedPreferences(Application app) {
    return PreferenceManager.getDefaultSharedPreferences(app);
}
}

PrefsModel.java:

PrefsModel.java:

@Module(includes = DataModule.class)
public class PrefsModel {

@Provides
@Singleton
QueryPreferences provideQuery(SharedPreferences prefs) {
    return new QueryPreferences(prefs);
}
}

AppComponent.java (I'm exposing QueryPreferences object since I need it in a presenter, hopefully is correct in this way):

AppComponent.java(我公开了 QueryPreferences 对象,因为我在演示者中需要它,希望以这种方式是正确的):

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

    void inject(HomeFragment homeFragment);

    QueryPreferences preferences();
    NetworkService networkService();
}

Then I have the FwApplication.java:

然后我有 FwApplication.java:

public class FwApplication extends Application {

private static final String TAG = "FwApplication";

private NetworkService mNetworkService;

private AppComponent mDataComponent;

    @Override
    public void onCreate() {
       super.onCreate();

       buildComponentAndInject();
    }

    public static AppComponent component(Context context) {
      return ((FwApplication)   context.getApplicationContext()).mDataComponent;
    }

    public void buildComponentAndInject() {
       mDataComponent = DaggerComponentInitializer.init(this);
    }

    public static final class DaggerComponentInitializer {
      public static AppComponent init(FwApplication app) {
        return DaggerAppComponent.builder()
                .appModule(new AppModule(app))
                .dataModule(new DataModule())
                .build();
    }
   }
}

Finally I added another module for the presenters:

最后,我为演示者添加了另一个模块:

@Module
public class PresenterModule {

   @Provides
   Presenter<FwView> provideHomePresenter(NetworkService networkService) {
      return new HomePresenterImpl(networkService);
   }

   @Provides
   Presenter<FwView> provideSearchPresenter(NetworkService networkService) {
      return new SearchPresenterImpl(networkService);
   }

}

And the following component (which returns error because I cannot add a scoped dependencies here):

以及以下组件(返回错误,因为我无法在此处添加作用域依赖项):

@Component(dependencies = AppComponent.class, modules = PresenterModule.class)
public interface PresenterComponent {

    void inject(HomePresenterImpl presenter);
}

So, I have few questions that are not clear for me reading the documentation online:

所以,我有几个问题不清楚我在线阅读文档:

  • How can I fix the error in the presenter component since it depends on NetworkService which is a singleton defined in the AppComponent?
  • I have an HomeFragment which should implement the HomePresenter with "new HomePresenter(networkService)" but now I don't know how to use the DI defined
  • 我如何修复演示器组件中的错误,因为它依赖于 NetworkService,它是 AppComponent 中定义的单例?
  • 我有一个 HomeFragment,它应该使用“new HomePresenter(networkService)”来实现 HomePresenter,但现在我不知道如何使用定义的 DI

EDIT - FIX:

编辑 - 修复:

HomeFragment.java:

HomeFragment.java:

public class HomeFragment extends Fragment {

private static final String TAG = "FW.HomeFragment";


@Inject
HomePresenterImpl mHomePresenter;

public static HomeFragment newInstance() {
    return new HomeFragment();
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    FwApplication.component(getActivity()).inject(this);
}

Then I modified the presenter constructor in this way:

然后我以这种方式修改了presenter构造函数:

@Inject
public HomePresenterImpl(NetworkService networkService) {
    mNetworkService = networkService;
    mInteractor = new InteractorImpl(mNetworkService);
}

Then NetworkService is injected automatically.

然后自动注入 NetworkService。

I was wondering if it is correct in this way since I have to call for every fragment I have that needs a presenter constructed in the same way as the one above the following code:

我想知道这种方式是否正确,因为我必须调用我拥有的每个片段,这些片段需要一个演示者,其构造方式与以下代码上方的相同:

FwApplication.component(getActivity()).inject(this);

回答by David Medenjak

You are mixing thing up. To provide your presenter, you should switch to something like the following:

你把事情搞混了。要提供您的演示者,您应该切换到以下内容:

Use constructor injection if possible. It will make things much easier

如果可能,请使用构造函数注入。这将使事情变得容易得多

public class HomePresenterImpl {

    @Inject
    public HomePresenterImpl(NetworkService networkService) {
        // ...
    }

}

To provide the interface use this constructor injection and dependon the implementation:

要提供接口,请使用此构造函数注入并依赖于实现:

Presenter<FwView> provideHomePresenter(HomePresenterImpl homePresenter) {
    return homePresenter;
}

This way you don't have to call any constructors yourself. And to actually injectthe presenter...

这样您就不必自己调用任何构造函数。并实际注入演示者......

public class MyFragment extends Fragment {

    @Inject
    Presenter<FwView> mHomePresenter;

    public void onCreate(Bundle xxx) {
        // simplified. Add your modules / Singleton component
        PresenterComponent component = DaggerPresenterComponent.create().inject(this);
    }
}

This way you will inject the things. Please read this carefully and try to understand it. This will fix your major problems, you still can not provide 2 presenters of the same type from the same module (in the same scope)

这样你就可以注入东西。请仔细阅读并尝试理解它。这将解决您的主要问题,您仍然无法从同一模块(在同一范围内)提供 2 个相同类型的演示者

// DON'T
@Provides
Presenter<FwView> provideHomePresenter(NetworkService networkService) { /**/ }

@Provides
Presenter<FwView> provideSearchPresenter(NetworkService networkService) { /**/ }

This will notwork. You can not provide 2 objects of the same kind. They are indistinguishable. Have a look at @Qualifierslike @Namedif you are sure this is the way you want to go.

将不工作。您不能提供 2 个相同类型的对象。它们是无法区分的。看看@Qualifiers@Named如果你确信这是你想要的路要走。

回答by Mladen Rakonjac

You do not have to provide Presenter if @Inject annotation is used in the constructor. @Inject annotation used in the constructor of the class makes that class a part of dependencies graph. So, it also can be injected when needed.

如果在构造函数中使用@Inject 注释,则不必提供 Presenter。类的构造函数中使用的@Inject 注释使该类成为依赖关系图的一部分。因此,它也可以在需要时注入。

On the other hand, if you add @Inject annotation to fields, but not to constructors, you have to provide that class.

另一方面,如果您将 @Inject 注释添加到字段而不是构造函数,则必须提供该类。