Я пытаюсь внедрить ведущего для моего Fragment через внедрение конструктора (так что мне не нужно создавать метод @Provides для ведущего).

Я считаю, что делаю это правильно, но по-прежнему получаю следующую ошибку:

MainFragmentPresenter не может быть предоставлен без метода аннотации @ Provides- или @ Produces.

Вот моя установка:

< Сильный > ApplicationComponent.java

@Singleton
@Component(
        modules = {
                NetworkModule.class
        }
)
public interface ApplicationComponent {

    NetworkService networkService();
}

MainFragmentComponent.java

@PerFragment
@Component(
        dependencies = ApplicationComponent.class,
        modules = MainFragmentPresenterModule.class
)
public interface MainFragmentComponent {

    MainFragmentView view();

    void inject(MainFragment mainFragment);
}

MainFragmentPresenterModule.java

@Module
public class MainFragmentPresenterModule {

    private final MainFragmentView _view;

    public MainFragmentPresenterModule(MainFragmentView view) {
        _view = view;
    }

    @Provides
    @PerFragment
    MainFragmentView provideMainFragmentView() {
        return _view;
    }
}

< Сильный > NetworkModule.java

@Module
public class NetworkModule {

    @Provides
    @Singleton
    OkHttpClient provide_OkHttpClient() {
        return new OkHttpClient();
    }

    @Provides
    @Singleton
    OpenWeatherEndpoints provide_OpenWeatherAPI(OkHttpClient client) {

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://api.openweathermap.org/data/2.5/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(client)
                .build();

        return retrofit.create(OpenWeatherEndpoints.class);

    }

    @Provides
    @Singleton
    YoutubeEndpoints provide_YoutubeEndpoints(OkHttpClient client) {

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://www.googleapis.com/youtube/v3/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(client)
                .build();

        return retrofit.create(YoutubeEndpoints.class);

    }

    @Provides
    @Singleton
    NetworkService provide_NetworkService(OpenWeatherEndpoints openWeatherEndpoints, YoutubeEndpoints youtubeEndpoints) {
        return new NetworkService(openWeatherEndpoints, youtubeEndpoints);
    }
}

PerFragment.java

@Scope
@Retention(RUNTIME)
@interface PerFragment {
}

MainFragmentPresenterImpl.java

public class MainFragmentPresenterImpl implements MainFragmentPresenter {
    private final MainFragmentView _view;
    private NetworkService _service;

    @Inject MainFragmentPresenterImpl(MainFragmentView view, NetworkService networkService) {
        _view = view;
        _service = networkService;
    }
}

И когда я пытаюсь вставить ведущего в свой фрагмент ...

public class MainFragment extends Fragment implements MainFragmentView {

    public static final String TAG = "MainFragment";

    @Inject
    MainFragmentPresenter _presenter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DaggerMainFragmentComponent.builder()
                .applicationComponent(WeatherForecastApp.get(getContext()).getAppComponent())
                .mainFragmentPresenterModule(new MainFragmentPresenterModule(this))
                .build()
                .inject(this);
   }
}

Любая помощь приветствуется! Благодарю.

1
Tmarsh2 24 Июн 2017 в 17:50

1 ответ

Лучший ответ

Вам нужно добавить привязку от MainFragmentPresenterImpl к MainFragmentPresenter. Dagger не выполняет преобразование между типами, поэтому вам нужно сделать это явно с помощью @Binds. @Binds эквивалентен методу @Provides, который просто возвращает свой аргумент, но он реализован более эффективно. Просто измените свой модуль следующим образом:

@Module
public abstract class MainFragmentPresenterModule {
    ...
    @Binds
    abstract MainFragmentPresenter(MainFragmentPresenterImpl impl);
}

Кроме того, вы можете избавиться от метода @Provides, поля _view и конструктора в модуле, используя @ BindsInstance.

public interface MainFragmentComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder mainFragmentView(MainFragmentView mainFragmentView);
    }
    void inject(MainFragment mainFragment);
}

Теперь, поскольку в вашем модуле нет конструктора, Dagger не нужно предоставлять экземпляр, поэтому вы можете создать компонент следующим образом:

DaggerMainFragmentComponent.builder()
    .applicationComponent(WeatherForecastApp.get(getContext()).getAppComponent())
    .mainFragmentView(this)
    .build()
    .inject(this);
1
aball 26 Июн 2017 в 00:57