Презентация с кинжалом 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);
   }

}

И следующий компонент (который возвращает ошибку, потому что здесь я не могу добавить зависимые области):

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

    void inject(HomePresenterImpl presenter);
}

Итак, у меня есть несколько вопросов, которые не ясны для чтения документации в Интернете:

  • Как я могу исправить ошибку в компоненте презентатора, так как он зависит от NetworkService, который является одноточечным, определенным в AppComponent?
  • У меня есть HomeFragment, который должен реализовать HomePresenter с "новым HomePresenter (networkService)", но теперь я не знаю, как использовать выбранный DI

EDIT - FIX:

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 вводится автоматически.

Мне было интересно, правильно ли это так, потому что мне нужно вызвать для каждого фрагмента, который у меня есть, который нуждается в презентаторе, сконструированном так же, как тот, который находится над следующим кодом:

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

Ответ 1

Вы все перепутали. Чтобы предоставить своего докладчика, вы должны переключиться на что-то вроде следующего:

Используйте конструктор инъекций, если это возможно. Это сделает вещи намного проще

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 если вы уверены, что именно так вы и хотите.

Ответ 2

Вам не нужно предоставлять Presenter, если в конструкторе используется аннотация @Inject. @Вводная аннотация, используемая в конструкторе класса, делает этот класс частью графика зависимостей. Таким образом, он также может быть введен в случае необходимости.

С другой стороны, если вы добавляете аннотацию @Inject к полям, но не к конструкторам, вы должны предоставить этот класс.