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!
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);