Search code examples
javaandroidretrofit2dagger-2android-annotations

I getting the following error using Dagger 2, Retrofit2 and AndroidAnnotations


i'm creating a MVP(Model View Presenter) project using Dagger 2(DI), Retrofit2 and AndroidAnnotations. But when injecting this component inside the main function in Activity.class:

((App) getApplication()).getNetComponent().inject(this);

I get the following error:

java.lang.NullPointerException: Cannot return null from a non-@Nullable 
@Provides method

find below attached my code: MainActivity.java:

@EActivity(R.layout.activity_main_view)
public class MainViewActivity extends AppCompatActivity implements SampleMainView {

  @Inject
  SampleMainPresenter sampleMainPresenter;

  @AfterViews
  void setupView(){
    ((App) getApplication()).getNetComponent().inject(this);
  }

}

App.java:

public class App extends Application {
  private NetComponent mNetComponent;

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

    mNetComponent = DaggerNetComponent.builder()
            .appModule(new AppModule(this))
            .netModule(new NetModule("http://www.bancaderiesgo.com/proyectos_admon/clases/"))
            .sampleMainPresenterModule(new SampleMainPresenterModule())
            .build();

  }

  public NetComponent getNetComponent() {
    return mNetComponent;
  }

}

AppModule.java:

@Module
public class AppModule {

  Application mApplication;

  public AppModule(Application application){
    this.mApplication = application;
  }

  @Provides
  @Singleton
  Application provideApplication(){
    return mApplication;
  }

}

NetModule.java:

 @Module
 public class NetModule {

  String mBaseUrl;

  public NetModule(String BaseUrl){
    this.mBaseUrl = BaseUrl;
  }

  @Provides
  @Singleton
  Cache provideHttpCache(Application application){
    int cacheSize = 10 * 1024 * 1024;
    Cache cache = new Cache(application.getCacheDir(), cacheSize);
    return  cache;
  }

  @Provides
  @Singleton
  Gson provideGson(){
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingPolicy(
         FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    return gsonBuilder.create();
  }

  @Provides
  @Singleton
  OkHttpClient provideOkHttpClient(Cache cache){
    OkHttpClient.Builder client = new OkHttpClient.Builder();
    client.cache(cache);
    return client.build();
  }

  @Provides
  @Singleton
  Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient){
    return new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create(gson))
            .baseUrl(mBaseUrl)
            .client(okHttpClient)
            .build();
  }

}

SampleMainPresenterModule.class

   @Module
   public class SampleMainPresenterModule {

      SampleMainView view;
      SampleMainInteractor sampleMainInteractor;

      @Provides
      @Singleton
      SampleMainView providesSampleMainView(){
        return view;
      }

      @Provides
      @Singleton
      SampleMainInteractor providesSampleInteractor(){
        return sampleMainInteractor;
      }

    }

SampleMainView.class

    public interface SampleMainView {

       void showMessage(String message);

       void showError(String error);

       void result(String msg);

   }

SampleMainInteractor.java

   public interface SampleMainInteractor {

      interface LoadListener {
        void onLoaded(List<String> items);
      }

      void loadItems(LoadListener listener);

    }

Does anyone know how to solve this error? Thanks!


Solution

  • The problem is in your MainPresenterModule:

    @Module
    public class SampleMainPresenterModule {
    
       SampleMainView view;
       SampleMainInteractor sampleMainInteractor;
    
       @Provides
       @Singleton
       SampleMainView providesSampleMainView(){
         return view; //null pointer here
       }
    
       @Provides
       @Singleton
       SampleMainInteractor providesSampleInteractor(){
         return sampleMainInteractor; //null pointer here
       }
    }
    

    Think about what happens when Dagger 2 tries to wire up your dependency graph in this case. You are saying "SampleMainView should be provided from the view field in this module" yet the the view field is never initialised.

    Modules for Presenters normally need constructors in which to pass in the View. Something like this:

    @Module
    public class SampleMainPresenterModule {
    
       SampleMainView view;
       SampleMainInteractor sampleMainInteractor;
    
       SampleMainPresenterModule(SampleMainView view, SampleMainInteractor interactor) {
           this.view = view;
           this.interactor = interactor;
       }
    
       @Provides
       @Singleton
       SampleMainView providesSampleMainView(){
         return view; 
       }
    
       @Provides
       @Singleton
       SampleMainInteractor providesSampleInteractor(){
         return sampleMainInteractor;
       }
    }
    

    Then there is the problem of where to initialise the MainPresenterModule. You are currently initialising it inside your Application subclass.

    This is probably not the right approach - you want to use a subcomponent or a dependent component and configure the component with the presenter module inside your Activity or Fragment. The tutorial or book you are following should explain this.

    If you were using dependent components (I think these are easier to start with) then you would do something like this in your Activity:

    void onCreate(Bundle savedInstanceState) { 
       super.onCreate(savedInstanceState);
       DaggerMainComponent.builder()
           .netComponent(((App)getApplication())
           .mainPresenterModule(new SampleMainPresenterModule(this, this))
           .build() 
           .inject(this);