使用 Dagger 2 进行 Presenter 注入
Presenter injection with Dagger 2
我刚开始使用 Dagger 2,我在网上发现了数千个指南,每个指南都有不同的实现,我现在有点困惑。
所以基本上这就是我现在写的:
AppModule.java:
@Module
public class AppModule {
Application mApplication;
public AppModule(Application application) {
mApplication = application;
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}
}
DataModule.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:
@Module(includes = DataModule.class)
public class PrefsModel {
@Provides
@Singleton
QueryPreferences provideQuery(SharedPreferences prefs) {
return new QueryPreferences(prefs);
}
}
AppComponent.java(我正在公开 QueryPreferences 对象,因为我在演示者中需要它,希望这种方式是正确的):
@Singleton
@Component(modules = {AppModule.class, DataModule.class, PrefsModel.class})
public interface AppComponent {
void inject(HomeFragment homeFragment);
QueryPreferences preferences();
NetworkService networkService();
}
然后我有 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();
}
}
}
最后我为演示者添加了另一个模块:
@Module
public class PresenterModule {
@Provides
Presenter<FwView> provideHomePresenter(NetworkService networkService) {
return new HomePresenterImpl(networkService);
}
@Provides
Presenter<FwView> provideSearchPresenter(NetworkService networkService) {
return new SearchPresenterImpl(networkService);
}
}
和以下组件(returns 错误,因为我无法在此处添加作用域依赖项):
@Component(dependencies = AppComponent.class, modules = PresenterModule.class)
public interface PresenterComponent {
void inject(HomePresenterImpl presenter);
}
所以,我有几个问题对我在线阅读文档不清楚:
- 如何修复 Presenter 组件中的错误,因为它依赖于 AppComponent 中定义的单例 NetworkService?
- 我有一个 HomeFragment,它应该使用 "new HomePresenter(networkService)" 实现 HomePresenter,但现在我不知道如何使用定义的 DI
编辑-修正:
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);
}
然后我把presenter的构造函数修改成这样:
@Inject
public HomePresenterImpl(NetworkService networkService) {
mNetworkService = networkService;
mInteractor = new InteractorImpl(mNetworkService);
}
然后自动注入NetworkService。
我想知道这种方式是否正确,因为我必须调用我拥有的每个片段,这些片段需要一个演示者,其构造方式与以下代码上面的片段相同:
FwApplication.component(getActivity()).inject(this);
你把事情搞混了。要提供您的演示者,您应该切换到类似以下内容:
尽可能使用构造函数注入。它会让事情变得更容易
public class HomePresenterImpl {
@Inject
public HomePresenterImpl(NetworkService networkService) {
// ...
}
}
要提供接口,请使用此构造函数注入并依赖实现:
Presenter<FwView> provideHomePresenter(HomePresenterImpl homePresenter) {
return homePresenter;
}
这样您就不必自己调用任何构造函数。并实际 注入 演示者...
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);
}
}
这样你就可以注入东西了。请仔细阅读并尝试理解它。这将解决你的主要问题,你仍然不能从同一模块(在同一范围内)提供 2 个相同类型的演示者
// DON'T
@Provides
Presenter<FwView> provideHomePresenter(NetworkService networkService) { /**/ }
@Provides
Presenter<FwView> provideSearchPresenter(NetworkService networkService) { /**/ }
这个不会工作。您不能提供 2 个同类对象。它们是无法区分的。如果您确定这是您想要的方式,请查看 @Qualifiers
和 @Named
。
如果在构造函数中使用@Inject 注解,则无需提供Presenter。 class 的构造函数中使用的 @Inject 注释使 class 成为依赖关系图的一部分。因此,它也可以在需要时注射。
另一方面,如果您将 @Inject 注释添加到字段而不是构造函数,则必须提供 class.
我刚开始使用 Dagger 2,我在网上发现了数千个指南,每个指南都有不同的实现,我现在有点困惑。 所以基本上这就是我现在写的:
AppModule.java:
@Module
public class AppModule {
Application mApplication;
public AppModule(Application application) {
mApplication = application;
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}
}
DataModule.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:
@Module(includes = DataModule.class)
public class PrefsModel {
@Provides
@Singleton
QueryPreferences provideQuery(SharedPreferences prefs) {
return new QueryPreferences(prefs);
}
}
AppComponent.java(我正在公开 QueryPreferences 对象,因为我在演示者中需要它,希望这种方式是正确的):
@Singleton
@Component(modules = {AppModule.class, DataModule.class, PrefsModel.class})
public interface AppComponent {
void inject(HomeFragment homeFragment);
QueryPreferences preferences();
NetworkService networkService();
}
然后我有 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();
}
}
}
最后我为演示者添加了另一个模块:
@Module
public class PresenterModule {
@Provides
Presenter<FwView> provideHomePresenter(NetworkService networkService) {
return new HomePresenterImpl(networkService);
}
@Provides
Presenter<FwView> provideSearchPresenter(NetworkService networkService) {
return new SearchPresenterImpl(networkService);
}
}
和以下组件(returns 错误,因为我无法在此处添加作用域依赖项):
@Component(dependencies = AppComponent.class, modules = PresenterModule.class)
public interface PresenterComponent {
void inject(HomePresenterImpl presenter);
}
所以,我有几个问题对我在线阅读文档不清楚:
- 如何修复 Presenter 组件中的错误,因为它依赖于 AppComponent 中定义的单例 NetworkService?
- 我有一个 HomeFragment,它应该使用 "new HomePresenter(networkService)" 实现 HomePresenter,但现在我不知道如何使用定义的 DI
编辑-修正:
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);
}
然后我把presenter的构造函数修改成这样:
@Inject
public HomePresenterImpl(NetworkService networkService) {
mNetworkService = networkService;
mInteractor = new InteractorImpl(mNetworkService);
}
然后自动注入NetworkService。
我想知道这种方式是否正确,因为我必须调用我拥有的每个片段,这些片段需要一个演示者,其构造方式与以下代码上面的片段相同:
FwApplication.component(getActivity()).inject(this);
你把事情搞混了。要提供您的演示者,您应该切换到类似以下内容:
尽可能使用构造函数注入。它会让事情变得更容易
public class HomePresenterImpl {
@Inject
public HomePresenterImpl(NetworkService networkService) {
// ...
}
}
要提供接口,请使用此构造函数注入并依赖实现:
Presenter<FwView> provideHomePresenter(HomePresenterImpl homePresenter) {
return homePresenter;
}
这样您就不必自己调用任何构造函数。并实际 注入 演示者...
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);
}
}
这样你就可以注入东西了。请仔细阅读并尝试理解它。这将解决你的主要问题,你仍然不能从同一模块(在同一范围内)提供 2 个相同类型的演示者
// DON'T
@Provides
Presenter<FwView> provideHomePresenter(NetworkService networkService) { /**/ }
@Provides
Presenter<FwView> provideSearchPresenter(NetworkService networkService) { /**/ }
这个不会工作。您不能提供 2 个同类对象。它们是无法区分的。如果您确定这是您想要的方式,请查看 @Qualifiers
和 @Named
。
如果在构造函数中使用@Inject 注解,则无需提供Presenter。 class 的构造函数中使用的 @Inject 注释使 class 成为依赖关系图的一部分。因此,它也可以在需要时注射。
另一方面,如果您将 @Inject 注释添加到字段而不是构造函数,则必须提供 class.