Dagger 2中的Presenter注入

11

我刚开始使用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对象公开,因为我在Presenter中需要它,希望这样是正确的):

AppComponent.java(我将QueryPreferences对象公开,因为我在Presenter中需要它,希望这样是正确的):

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

}

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

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

    void inject(HomePresenterImpl presenter);
}

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

  • 由于 Presenter 组件依赖于 NetworkService(在 AppComponent 中定义的单例),我该如何修复错误?
  • 我有一个 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);
}

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

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

然后NetworkService会自动注入。

我想知道这种方式是否正确,因为我不得不为每个需要以与上面相同的方式构建presenter的片段调用以下代码:

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

请修复Presenter组件中的错误。请始终包括错误信息。 - David Medenjak
1
onCreate() 中使用 getAactivity() 可能会产生 NullPointerException。https://dev59.com/eG025IYBdhLWcg3wHR4Y#6225044 - Bresiu
2个回答

14
你把事情搞混了。为了提供你的演示文稿,你应该切换到类似以下的东西:
如果可能的话,请使用构造函数注入。这将使事情变得更加容易。
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);
    }
}

这样你就可以注入这些东西了。请仔细阅读并尝试理解。这将解决你的主要问题,但你仍然不能从同一模块(在同一作用域内)提供两个相同类型的演示者。

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

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

这个做法是不可行的。你不能提供两个相同类型的对象,它们是无法区分的。请查看@Qualifiers,例如 @Named,如果你确定要这样做。


非常感谢您的回答,我编辑了问题以展示我是如何按照您的建议修复它的。(我不确定我在片段中进行Presenter注入的方式是否正确) - user1341300
3
针对你的 return homePresenter;,你可以使用 @Binds 注解来生成更好的后台代码。请参见 https://google.github.io/dagger/faq.html#binds 和 https://google.github.io/dagger/api/latest/dagger/Binds.html - TWiStErRob
非常感谢!我自己也为此问题苦苦挣扎过。这解开了我一些疑惑。再次感谢你。 - taitasciore
@David,唯一缺少的是如何以可模拟的方式将视图传递给Presenter。 - saiedmomen

7

如果构造函数中使用了@Inject注释,您无需提供Presenter。在类的构造函数中使用@Inject注释会使该类成为依赖项图的一部分。因此,在需要时也可以进行注入。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接