2017-12-20 55 views
0

Android 용 Dagger2.13과 관련하여 도움이 필요합니다.Subcomponent.Builder에 setter가 없습니다.

인터넷에서 몇 가지 예를 사용하고 있지만 현재 해결할 수없는 오류가 있습니다.

문제 클래스를 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(); 
    } 

} 

-ViewBuilderMod ule-

@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-

012,351 6,
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

항상 질문 자체에 문제를 재현 할 수있는 최소한의 코드를 기입하십시오. 어제 비슷한 문제가있는 사람이있었습니다. https://stackoverflow.com/a/47891181/1837367 –

답변

1

당신은 당신의 모듈이 필요합니다

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

그리고 공공 매개 변수가없는 생성자가 없기 때문에 단검은 그것을 만들 수 없습니다 :

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

하지만 빌더에서 직접 바인딩 :

@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 인스턴스를 제공하지 않았 음을 통지.

@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 : 당신은 SO, 또는 DIMarcaComponent.Builder #의 seedInstance를 재정 의하여 DIMarcaModulo에게 MarcaFragment를 주입 할 수있는 공공 매개 변수가없는 생성자를 제공하거나 의미 Dagger 2.10 Android subcomponents and builders을 의문을 제기의 조언을 따라야합니다 DIMarcoModulo가 설치하는 그래프에서 자동으로 사용할 수 있으므로 생성자 매개 변수를 피하고 조각을 a parameter to @Provides methods으로 수신하면 코드를 읽기가 더 쉬울 수 있습니다.onAttach을 주사하고 RecyclerView onCreateView에 액세스 할 수 있기 때문에 fragment.getMMarcaAdapter()라고 불리는 방법에도 문제가 있습니다. 그러나 생성자 매개 변수를 제거하고 Android가 생성 할 때까지 RecyclerView에 액세스하지 않도록 할 수 있다면 큰 문제는 아닙니다.

+0

감사합니다. Jeff Bowman, 알겠습니다. 하지만 또 다른 문제가있었습니다. 아마 거기에 있었지만 나는 그것을 보지 못했습니다. 이제 FipeApplication 내부에서 DaggerDIApplicationComponent를 호출하면 빌드가 완료된 후에도 나타나지 않습니다. 누구든지 나를 도와 줄 수 있습니까? – Hugo

+0

@Hugo Dagger는 Java 컴파일 프로세스의 일부로 실행되므로 작성한 코드에 구문 오류가 있거나 사용자가 정의한'@ Component'에서 대거 종속성 오류가 발생하면 구성 요소 구현이 생성되지 않습니다 . Dagger 오류와 관련된 로그에서 오류 메시지를 찾으십시오. 오류 메시지를 이해하는 데 어려움이있는 경우 여기에 게시하십시오 (별도의 최상위 수준 질문 일 수 있음). –

1

감사합니다. 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'