Dagger Nullpointerexception 3rd class which depends on 2nd class

Asked

Viewed 58 times

0

In a project that has the Activity, Presenter and a Model, the Activity has the Presenter and the Presenter has a Model. When I do @Inject in the Presenter to instantiate the Model it is never instantiated.

FATAL EXCEPTION: main Process: fipedaggerrxjava, PID: 22258 java.lang.Nullpointerexception: Attempt to invoke interface method 'void fipedaggerrxjava.mvp.Selectmarcacontractmvp$Model.getMarcas(java.lang.String)' on a null Object Reference at fipedaggerrxjava.module.brand.MarcaPresenter.initData(Marcapresenter.java:35) at fipedaggerrxjava.module.marca.Marcaactivity$1.onCheckedChanged(Marcaactivity.java:63)

I have checked in Debug and really the Model that is not being instantiated by Dagger but I can not understand why.

App

public class App extends Application implements HasActivityInjector{

    @Inject
    public DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;


    @Override
    public void onCreate() {
        super.onCreate();
        DaggerAppComponent.builder().build().inject(App.this);
    }

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

Activitybuilder

@Module
public abstract class ActivityBuilder {

    @Binds
    @IntoMap
    @ActivityKey(MarcaActivity.class)
    abstract AndroidInjector.Factory<? extends Activity> bindMarcaActivity (MarcaComponent.Builder builder);

}

Appcomponent

@Component(modules = {ActivityBuilder.class, AndroidInjectionModule.class, AppModule.class})
@Singleton
public interface AppComponent {

    void inject(App app);

}

Appmodule

@Module(subcomponents = MarcaComponent.class)
public class AppModule {

    @Provides
    @Singleton
    @Named("URL_MARCA")
    String provideStringURLBase(){
        return "https://fipe.parallelum.com.br/api/v1/";
    }

    @Provides
    @Singleton
    Context provideContext(App app){
        return app;
    }

    @Provides
    @Singleton
    Gson provideGsonRepositorie(){
        return new GsonBuilder()
                .create();
    }


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


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


    @Provides
    @Singleton
    Retrofit provideRetrofit(OkHttpClient okHttpClient, Gson gson, RxJavaCallAdapterFactory rxAdapter, @Named("URL_MARCA") String stringBaseURL){
        return new Retrofit.Builder()
                .baseUrl(stringBaseURL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(rxAdapter)
                .client(okHttpClient)
                .build();
    }
}

Marcacomponent

@Subcomponent(modules = MarcaModule.class)
@PerMarca
public interface MarcaComponent extends AndroidInjector<MarcaActivity>{

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MarcaActivity> {}

}

Marcamodule

@Module
public class MarcaModule{


    @Provides
    @PerMarca
    APIFIPE provideAPIFIPE(Retrofit retrofit){
        return retrofit.create(APIFIPE.class);
    }


    @Provides
    @PerMarca
    View provideViewMarca(MarcaActivity activity){
        return activity;
    }


    @Provides
    @PerMarca
    Presenter providePresenterMarca(){
        return new MarcaPresenter();
    }


    @Provides
    @PerMarca
    Model provideModelMarca(){
        return new MarcaModel();
    }


}

Adaptermarca

public class AdapterMarca extends BaseAdapter {

private List<Marca> mListMarca;

@Inject
public Context mContext;

public AdapterMarca(List<Marca> listMarca){
    this.mListMarca = listMarca;
}


@Override
public int getCount() {
    return mListMarca.size();
}

@Override
public Object getItem(int position) {
    return mListMarca.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.layout_list_item, parent, false);

    TextView tvNome = view.findViewById(R.id.tv_marca);
    tvNome.setText(mListMarca.get(position).getName().toString());

    return view;
}


public void addListMarca(List<Marca> marcaList){
    mListMarca.clear();
    mListMarca.addAll(marcaList);
    notifyDataSetChanged();
}

}

Marcaactivity

public class MarcaActivity extends BaseActivity implements HasActivityInjector, View {

    private RadioGroup radioGroupMarca;
    private String tipoSelect = "";

    private List<Marca> mListMarca;
    private AdapterMarca mAdapterMarca;

    private ListView listViewMarca;


    @Inject
    public Presenter mMarcaPresenter;

    @Inject
    protected DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(MarcaActivity.this);
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        listViewMarca = findViewById(R.id.lv_marca);


        radioGroupMarca = findViewById(R.id.rg_tipo);

        radioGroupMarca.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                int id = group.getCheckedRadioButtonId();

                switch (id){
                    case R.id.rb_carros : tipoSelect = "carros";
                        mMarcaPresenter.initData(tipoSelect);
                        break;

                    case R.id.rb_motos : tipoSelect = "motos";
                        mMarcaPresenter.initData(tipoSelect);
                        break;

                    case R.id.rb_caminhoes : tipoSelect = "caminhoes";
                        mMarcaPresenter.initData(tipoSelect);
                        break;
                }
            }
        });



    }



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



    @Override
    public void onMarcaLoader(List<Marca> listMarcas) {
        if(mListMarca==null && listMarcas!=null){
            initListView();
        }

        if(mAdapterMarca!=null){
            mListMarca.clear();
            mListMarca = listMarcas;

            mAdapterMarca.addListMarca(mListMarca);
        }

    }


    private void initListView(){
        mAdapterMarca = new AdapterMarca(mListMarca);
        listViewMarca.setAdapter(mAdapterMarca);
    }

}

Marcapresenter

@PerMarca
public class MarcaPresenter implements Presenter {

    @Inject
    View mMarcaView;


    @Inject
    Model mMarcaModel;

    @Inject
    public MarcaPresenter(){

    }


    @Override
    public void initData(String tipoMarca) {
        mMarcaModel.getMarcas(tipoMarca);
    }

    @Override
    public void getMarcas(List<Marca> listMarcas) {
        mMarcaView.onMarcaLoader(listMarcas);
    }

    @Override
    public void onShowDialog(String title, String msg) {
        mMarcaView.onShowDialog(title, msg);
    }

    @Override
    public void onHideShowDialog() {
        mMarcaView.onHideShowDialog();
    }

    @Override
    public void onShowToast(String s) {
        mMarcaView.onShowToast(s);
    }
}

Marcamodel

@PerMarca
public class MarcaModel implements Model {

    @Inject
    APIFIPE mApiFIPE;

    @Inject
    Presenter mMarcaPresenter;


    @Inject
    public MarcaModel(){

    }

    @Override
    public void getMarcas(String tipoVeiculo) {
        final List<Marca> marcaList = new ArrayList<>();
        Observable<List<Marca>> observable = mApiFIPE.getRepositories(tipoVeiculo);
        observable.subscribe(new Observer<List<Marca>>() {
            @Override
            public void onCompleted() {
                mMarcaPresenter.getMarcas(marcaList);
            }

            @Override
            public void onError(Throwable e) {
                mMarcaPresenter.onShowDialog("Erro", "Falha ao carregar lista de marcas");
            }

            @Override
            public void onNext(List<Marca> marcas) {
                marcaList.addAll(marcas);
            }
        });



    }
}

1 answer

0

Let Dagger automatically inject yours Presenter and Model from the dependency graph, i.e., need not instantiate them within the module.

There is also a better way to inject activity into Android with annotation: @ContributesAndroidInjector, will greatly decrease codes Boilerplate. Here is a great article indicating how to do it: https://medium.com/@iammert/new-android-injector-with-Dagger-2-part-2-4af05fd783d0

EDIT

I’ve made some changes to your classes. You should not instantiate your objects, but do the control inversion, ie, Dagger will instantiate them for you.

Marcamodule

@Module
public class MarcaModule{
    ....

    @Provides
    @PerMarca
    Presenter providePresenterMarca(MarcaPresenter presenter){
        return presenter;
    }

    @Provides
    @PerMarca
    Model provideModelMarca(MarcaModel marca){
        return marca;
    }
}

Marcaactivity

public class MarcaActivity extends BaseActivity implements HasActivityInjector, View {
    ....

    @Inject
    AdapterMarca mAdapterMarca;

    ....

    private void initListView(){
        mAdapterMarca.addListMarca(mListMarca);
        listViewMarca.setAdapter(mAdapterMarca);
    }

}

Adaptermarca

public class AdapterMarca extends BaseAdapter {

    private List<Marca> mListMarca;

    @Inject
    Context mContext;

    public AdapterMarca(){
        this.mListMarca = new ArrayList();
    }
    ...
}
  • "Let Dagger automatically inject your Presenter and Model from the dependency graph, meaning you don’t need to instantiate them within the module." But how would I do that? And this question of having Class A that has B and B that has C. Class B should be able to instantiate @Inject Class C normally or I have something special to do?

  • If B is injected by Dagger and depends on C, then C will be injected as well, provided C has the annotation @Inject.

  • I have tried several ways and I can’t get the model to receive an object from Degger with @Inject. Always from Nullpointerexception. Caique suggested above not to instantiate in Module but to let Dagger instantiate automatically, but how do I do this?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.