Презентация с кинжалом 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 к полям, но не к конструкторам, вы должны предоставить этот класс.