我需要Android Dagger2.13的帮助。
我正在互联网上关注几个示例,但现在遇到了无法解决的错误。
错误:(23、14)错误:@ Subcomponent.Builder缺少所需模块或子组件的设置器:[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 DispatchingAndroidInjectordispatchingAndroidInjectorFragment; @Inject DispatchingAndroidInjector 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 fragmentInjector() { return dispatchingAndroidInjectorFragment; } @Override public AndroidInjector 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{ @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{ @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder { } }
-MarcaFragment-
public class MarcaFragment extends BaseFragment implements IMarcaView, HasFragmentInjector{ private MarcaAdapterRecyclerImpl mMarcaAdapter; private LinearLayoutManager llm; private View view = null; @Inject DispatchingAndroidInjectorfragmentDispatchingAndroidInjector; @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 fragmentInjector() { return fragmentDispatchingAndroidInjector; } }
-MarcaPresenterImpl-
public class MarcaPresenterImpl extends BasePresenterimplements 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 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> { @Inject public IMarcaPresenter mPresenter; @Inject public IMarcaAPI mMarcaAPI; private List
listMarca; @Inject public ControllerServiceAPIRest() { } protected void getMarca(){ if(listMarca == null){ listMarca = new ArrayList<>(); } mPresenter.onShowProgress("Carregando Marca de Veículos..."); Observable > cakesRespOnseObservable= mMarcaAPI.getAllMarca(); subscribe(cakesResponseObservable, this); } private void subscribe(Observable
> observable, Observer
> 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
list) { listMarca = list; } }
Jeff Bowman .. 5
您需要您的模块:
@PerFragment @Subcomponent(modules = {DIMarcaModulo.class}) public interface DIMarcaComponent extends AndroidInjector{
而且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); }
因此,当dagger.android尝试创建您的对象时:
// AndroidInjector.Builder abstract class Builderimplements AndroidInjector.Factory { @Override public final AndroidInjector create(T instance) { seedInstance(instance); return build(); }
它会注意到您尚未提供DIMarcaModulo实例,并且失败了。您需要遵循SO问题Dagger 2.10 Android子组件和构建器中的建议,这意味着要么给DIMarcaModulo一个可以注入MarcaFragment的公共无参数构造函数,要么重写DIMarcaComponent.Builder#seedInstance:
@Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder{ // 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安装的图中自动可用,因此,如果您可以避免使用构造函数参数,而将片段作为@Provides方法的参数来接收,则代码可能更易于阅读。您也会遇到我调用的方法的麻烦fragment.getMMarcaAdapter()
,因为您进行了注入onAttach
并可以访问RecyclerView onCreateView
。但是,如果您删除了构造函数参数,并且可以确保在Android有机会创建RecyclerView之前,不要尝试访问RecyclerView,那么这应该不是一个大问题。
您需要您的模块:
@PerFragment @Subcomponent(modules = {DIMarcaModulo.class}) public interface DIMarcaComponent extends AndroidInjector{
而且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); }
因此,当dagger.android尝试创建您的对象时:
// AndroidInjector.Builder abstract class Builderimplements AndroidInjector.Factory { @Override public final AndroidInjector create(T instance) { seedInstance(instance); return build(); }
它会注意到您尚未提供DIMarcaModulo实例,并且失败了。您需要遵循SO问题Dagger 2.10 Android子组件和构建器中的建议,这意味着要么给DIMarcaModulo一个可以注入MarcaFragment的公共无参数构造函数,要么重写DIMarcaComponent.Builder#seedInstance:
@Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder{ // 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安装的图中自动可用,因此,如果您可以避免使用构造函数参数,而将片段作为@Provides方法的参数来接收,则代码可能更易于阅读。您也会遇到我调用的方法的麻烦fragment.getMMarcaAdapter()
,因为您进行了注入onAttach
并可以访问RecyclerView onCreateView
。但是,如果您删除了构造函数参数,并且可以确保在Android有机会创建RecyclerView之前,不要尝试访问RecyclerView,那么这应该不是一个大问题。