我需要帮助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;
}
}
答案 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'