Subcomponent.Builder缺少setter

时间:2017-12-20 12:53:10

标签: java android dependency-injection dagger-2 dagger

我需要帮助Dagger2.13 for Android。

我在互联网上关注了几个例子,但我现在面临一个我无法解决的错误。

  

错误:(23,14)错误:@ Subcomponent.Builder缺少setter for   必需的模块或子组件:   [com.hugothomaz.fipe.Module.DIMarcaModulo]

我认为最好在GITHub中发布问题类,并在此处包含存储库链接。

https://github.com/hugothomaz/FIPE_Test_Dagger2.11

-FipeApplication -

public class FipeApplication extends Application implements HasActivityInjector, HasFragmentInjector{

    private static final String URL_SEARCH = "http://fipeapi.appspot.com/api/1/";



    @Inject
    DispatchingAndroidInjector<Fragment> dispatchingAndroidInjectorFragment;

    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjectorActivity;


    @Override
    public void onCreate() {
        super.onCreate();
        initializeApplicationComponente();

    }


    @Override
    public void onTerminate() {
        super.onTerminate();
    }



    private void initializeApplicationComponente() {
        Log.i("app", "FipeApplication initializeApplicationComponente");
        //DaggerDIApplicationComponent.builder().(this).build();

    }



    @Override
    public AndroidInjector<Fragment> fragmentInjector() {
        return dispatchingAndroidInjectorFragment;
    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjectorActivity;
    }
}

-DIApplicationModulo -

@Module(subcomponents = {DIMarcaComponent.class})
public class DIApplicationModulo {

    @Provides
    @Singleton
    GsonConverterFactory provideGsonConverterFactory(){
        GsonConverterFactory factory = GsonConverterFactory.create();
        return factory;
    }

    @Provides
    @Singleton
    OkHttpClient provideOkHttpClient(){
        return new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .build();
    }

    @Provides
    @Singleton
    RxJavaCallAdapterFactory provideRxJavaCallAdapterFactory(){
        return RxJavaCallAdapterFactory.create();
    }

    @Provides
    @Singleton
    Retrofit provideRetrofit(OkHttpClient client,
                             GsonConverterFactory converterFactory,
                             RxJavaCallAdapterFactory adapterFactory, String mBaseURL){
        return new Retrofit.Builder()
                .baseUrl(mBaseURL)
                .addConverterFactory(converterFactory)
                .addCallAdapterFactory(adapterFactory)
                .client(client)
                .build();
    }

}

-DIApplicationComponent -

@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        DIApplicationModulo.class,
        ViewBuilderModule.class
        })
public interface DIApplicationComponent extends AndroidInjector<FipeApplication>{

    @Component.Builder
    interface Builder{
        @BindsInstance
        DIApplicationComponent.Builder baseURL(String mBaseURL);

        DIApplicationComponent build();
    }

}

-ViewBuilderModule -

@Module(subcomponents = {DIMarcaComponent.class})
public abstract class ViewBuilderModule {

    @Binds
    @IntoMap
    @FragmentKey(MarcaFragment.class)
    abstract AndroidInjector.Factory<? extends Fragment> bindMarcaFragment(DIMarcaComponent.Builder bulder);
}

-DIMarcaModulo -

@Module
public class DIMarcaModulo {

    private MarcaFragment mView;
    private MarcaAdapterRecyclerImpl mAdapter;
    public Context mContext;


    public DIMarcaModulo(MarcaFragment view, MarcaAdapterRecyclerImpl adapter){
        this.mView = view;
        this.mAdapter = adapter;
        this.mContext = view.getActivity().getBaseContext();
        Log.i("app", "DIMarcaModulo instanciado");
        if(adapter==null){
            Log.i("app", "DIMarcaModulo - adapter : nao instanciado");
        }else{
            Log.i("app", "DIMarcaModulo - adapter : instancied");
        }
    }


    @Provides
    @PerFragment
    IMarcaAPI provideMarcaApi(Retrofit retrofit){
        Log.i("app", "DIMarcaModulo provideMarcaApi");
        return retrofit.create(IMarcaAPI.class);
    }


    @Provides
    @PerFragment
    BaseView provideMarcaFragment(){
        Log.i("app", "DIMarcaModulo provideMarcaFragment");
        return mView;
    }


    @Provides
    @PerFragment
    IMarcaAdapterModel provideMarcaAdapterModel(){
        Log.i("app", "DIMarcaModulo provideMarcaAdapterModel");
        return mAdapter;
    }


    @Provides
    @PerFragment
    IMarcaPresenter provideMarcaPresenter(){
        Log.i("app", "DIMarcaModulo provideMarcaPresenter");
        return new MarcaPresenterImpl();
    }


    @Provides
    @PerFragment
    ControllerServiceAPIRest provideControllerServiceAPIRest(){
        Log.i("app", "DIMarcaModulo ControllerServiceAPIRest");
        return new ControllerServiceAPIRest();
    }

    @Provides
    @PerFragment
    Context exposeContext() {
        return mContext;
    }

}

-DIMarcaComponent -

@PerFragment
@Subcomponent(modules = {DIMarcaModulo.class})
public interface DIMarcaComponent extends AndroidInjector<MarcaFragment> {

   @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MarcaFragment>{

   }

}

-MarcaFragment -

public class MarcaFragment extends BaseFragment implements IMarcaView, HasFragmentInjector{


    private MarcaAdapterRecyclerImpl mMarcaAdapter;
    private LinearLayoutManager llm;
    private View view = null;


    @Inject
    DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;

    @Inject
    public IMarcaPresenter mMarcaPresenter;

    @BindView(R.id.rv_marca)
    protected RecyclerView mRecyclerMarca;
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {



        if(view==null){
             view = inflater.inflate(R.layout.fragment_marca, container, false);
         }
         setUnBinder(ButterKnife.bind(this, view));

        return view;
    }

    @Override
    protected void onViewReady(Bundle saveInstanceState, Intent intent) {
        initializeRecyclerMarca();
        super.onViewReady(saveInstanceState, intent);

        if(mMarcaPresenter != null){
            Log.i("app", "MarcaFragment - Presenter nao esta vazio");
        }else{
            Log.i("app", "MarcaFragment - Presenter esta vazio");
        }

        mMarcaPresenter.initSerice();
    }

    private void initializeRecyclerMarca() {
        if(mMarcaAdapter==null){
            mMarcaAdapter = new MarcaAdapterRecyclerImpl();
        }

        mRecyclerMarca.setHasFixedSize(true);
        llm = new LinearLayoutManager(getActivity().getBaseContext());
        llm.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerMarca.setLayoutManager(llm);
        mRecyclerMarca.setAdapter(mMarcaAdapter);
    }


    @Override
    public void onOpenVehicleFragmentByMarcaClicked(Marca marca) {
        // recebendo o item clicado para chamar proxima tela com a Marca clicada.
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        AndroidInjection.inject(this);
    }

    @Override
    public AndroidInjector<Fragment> fragmentInjector() {
        return fragmentDispatchingAndroidInjector;
    }
}

-MarcaPresenterImpl -

public class MarcaPresenterImpl extends BasePresenter<IMarcaView> implements IMarcaPresenter{

    private static final String TAG_MARCA_PRESENTER = "MarcaPresenterImpl";

    @Inject
    public IMarcaAdapterModel mMarcaAdapterModel;

    @Inject
    public ControllerServiceAPIRest mControllerServiceAPIRest;



    @Inject
    public MarcaPresenterImpl(){

    }

    @Override
    public void onShowMessage(String message) {
        getView().onShowMessage(message);
    }

    @Override
    public void onHideMessage() {
        getView().onHideMessage();
    }

    @Override
    public void onShowProgress(String message) {
        getView().onShowProgress(message);
    }

    @Override
    public void onHideProgress() {
        getView().onHideProgress();
    }

    @Override
    public void onShowToast(String message) {
        getView().onShowToast(message);
    }

    public void refresh() {
        mMarcaAdapterModel.refresh();
    }

    @Override
    public void refreshItem(int id) {

    }

    @Override
    public void listMarcaByServiceForView(List<Marca> listMarca) {
        mMarcaAdapterModel.setListMarca(listMarca);
    }

    @Override
    public void initSerice() {
        mControllerServiceAPIRest.getMarca();
    }

    @Override
    public void getMarcaClicked(@NonNull Marca marca) {
        getView().onOpenVehicleFragmentByMarcaClicked(marca);
    }


}

-ControllerServiceAPIRest -

public class ControllerServiceAPIRest implements Observer<List<Marca>> {

    @Inject
    public IMarcaPresenter mPresenter;

    @Inject
    public IMarcaAPI mMarcaAPI;

    private List<Marca> listMarca;

    @Inject
    public ControllerServiceAPIRest() {

    }



    protected void getMarca(){
        if(listMarca == null){
            listMarca = new ArrayList<>();
        }
        mPresenter.onShowProgress("Carregando Marca de Veículos...");

        Observable<List<Marca>> cakesResponseObservable = mMarcaAPI.getAllMarca();
        subscribe(cakesResponseObservable, this);
    }

    private void subscribe(Observable<List<Marca>> observable, Observer<List<Marca>> observer){

        observable.subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }


    @Override
    public void onError(Throwable e) {
        mPresenter.onHideMessage();
        mPresenter.onHideProgress();
        mPresenter.onShowToast("Erro ao carregar Marcas!");
        Log.e("app", "Falha no carregamento de Marcas: " + e.getMessage());
        new Exception(e.getMessage());
    }

    @Override
    public void onComplete() {
        mPresenter.onHideMessage();
        mPresenter.onHideProgress();

        Log.i("app", "ControllerServiceAPIRest - listMarca Position 0: " + listMarca.get(0));
        if (listMarca==null && !listMarca.isEmpty() && listMarca.get(0)!=null){
            mPresenter.listMarcaByServiceForView(listMarca);
            mPresenter.onShowToast("Marcas carregadas!");
        }else{
            mPresenter.onShowToast("Lista não foi carregada!");
        }

    }

    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(List<Marca> list) {
        listMarca = list;
    }
}

2 个答案:

答案 0 :(得分:5)

您需要您的模块:

@PerFragment
@Subcomponent(modules = {DIMarcaModulo.class})
public interface DIMarcaComponent extends AndroidInjector<MarcaFragment> {

Dagger无法创建它,因为它没有公共无参数构造函数:

@Module
public class DIMarcaModulo {
    // ...
    public DIMarcaModulo(MarcaFragment view, MarcaAdapterRecyclerImpl adapter){

但你直接在你的Builder中绑定:

@Module(subcomponents = {DIMarcaComponent.class})
public abstract class ViewBuilderModule {

    @Binds
    @IntoMap
    @FragmentKey(MarcaFragment.class)
    abstract AndroidInjector.Factory<? extends Fragment>
        bindMarcaFragment(DIMarcaComponent.Builder bulder);
}

所以when dagger.android tries to create your object

// AndroidInjector.Builder
abstract class Builder<T> implements AndroidInjector.Factory<T> {
  @Override
  public final AndroidInjector<T> create(T instance) {
    seedInstance(instance);
    return build();
  }

它注意到您没有提供DIMarcaModulo实例并失败。您需要遵循SO问题Dagger 2.10 Android subcomponents and builders中的建议,这意味着要么给DIMarcaModulo一个可以注入MarcaFragment的公共无参数构造函数,要么覆盖DIMarcaComponent.Builder#seedInstance:

@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MarcaFragment> {

  // This method tells Dagger you need to supply your own DIMarcoModulo.
  public abstract void diMarcoModulo(DIMarcaModulo modulo);

  // dagger.android calls this method automatically, but only this method, so
  // you'll need to call diMarcoModulo from it.
  @Override public void seedInstance(MarcaFragment fragment) {
    diMarcoModulo(fragment, fragment.getMMarcaAdapter());
    bindMarcaFragment(fragment);  // OPTIONAL: See below
  }

  // If you want MarcaFragment to remain injectable, you might need to call into
  // a different @BindsInstance method you define, because you've prevented
  // seedInstance from doing that for you.
  @BindsInstance public abstract void bindMarcaFragment(MarcaFragment fragment);
}

如您所见,MarcaFragment将自动在DIMarcoModulo安装的图形中可用,因此如果您可以避免构造函数参数而是接收片段a parameter to @Provides methods,则您的代码可能更容易阅读。您也会遇到我调用fragment.getMMarcaAdapter()的方法的问题,因为您注入onAttach并且可以访问RecyclerView onCreateView。但是,如果您删除构造函数参数并且确保在Android有机会创建它之前您不能尝试访问RecyclerView,这不应该是一个大问题。

答案 1 :(得分:2)

感谢Jeff Bowman,我的依赖是错误的。

现在它的工作原理如下:

 annotationProcessor "com.google.dagger:dagger-compiler:2.13"
   annotationProcessor "com.google.dagger:dagger-android-processor:2.13"
   compile "com.google.dagger:dagger:2.13"
   compile "com.google.dagger:dagger-android:2.13"
   compile 'com.google.dagger:dagger-android-support:2.13'