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

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

Related

Dagger2+Retrofit change URL with Subcomponent : cannot be provided without an #Provides- or #Produces-annotated method

I'm newbie in Dagger .I've used this answer to change URL at Runtime.
Also I've used three modules and three components as shown below:
note : I have tow Components (ApplicationComponent,ActivityComponent) and one Subcomponent(UrlComponent) In additation I use #Singletone,#PerUrl and #PerActivty as a Scope.
When I want to Inject RestApi into every Activity I encounter this Error :
error: com.example.testdagger2.RestApi cannot be provided without an #Provides- or #Produces-annotated method.
com.example.dagger2.RestApi is injected at
com.example.dagger2.RestApiHelper.restApi
com.example.dagger2.RestApiHelper is injected at
com.example.dagger2.MainActivity.restApiHelper
com.example.testdagger2.MainActivity is injected at
com.example.testdagger2.di.component.ActivityComponent.inject(mainActivity)
Before I had to change the URL in Runtime, I had two Component and modules (appCompoent and activtyComponent), and all the Providers (like Retrofit and RestApi ,...) were in the applicationModule and the program worked fine.
ApplicationComponent.java
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(ExampleApplication exampleApplication);
#ApplicationContext
Context context();
Application application();
UrlComponent plus(UrlModule component);
}
ApplicationModule.java
#Module
public class ApplicationModule {
private Application mApplication;
public ApplicationModule(Application application) {
this.mApplication = application;
}
#Provides
#ApplicationContext
Context provideContext() {
return mApplication;
}
#Provides
Application provideApplication() {
return mApplication;
}
}
UrlComponent.java
#PerUrl
#Subcomponent(modules = UrlModule.class)
public interface UrlComponent {
}
UrlModule.java
#Module
public class UrlModule {
private String url;
public UrlModule(String url) {
this.url = url;
}
#Provides
#PerUrl
OkHttpClient provideOkhttpClient() {
return new OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build();
}
#Provides
#PerUrl
Retrofit provideRetrofit(String baseURL, OkHttpClient client) {
return new Retrofit.Builder()
.baseUrl(baseURL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
#Provides
RestApiHelper provideRestApiHelper(RestApiHelper restApiManager) {
return restApiManager;
}
#Provides
public RestApi provideApiService() {
return provideRetrofit(url, provideOkhttpClient())
.create(RestApi.class);
}
}
ActivityComponent.java
#PerActivity
#Component(modules = ActivityModule.class,dependencies = ApplicationComponent.class)
public interface ActivityComponent {
void inject(MainActivity mainActivity);
.
.
.
}
ActivityModule.java
#Module
public class ActivityModule {
private AppCompatActivity mActivity;
public ActivityModule(AppCompatActivity mActivity) {
this.mActivity = mActivity;
}
#Provides
#ActivityContext
Context provideContext() {
return mActivity;
}
#Provides
AppCompatActivity provideActivity() {
return mActivity;
}
.
.
.
}
RestApi.java
public interface RestApi {
Single<Object> getquestionlist(#Query("page") int page);
Single<Object> getCategoryList();
}
RestApiHelper.java
public class RestApiHelper implements RestApi {
#Inject
RestApi restApi;
#Inject
public RestApiHelper(RestApi restApi) {
this.restApi = restApi;
}
#Override
public Single<Object> getquestionlist(int page) {
return restApi.getquestionlist(1);
}
#Override
public Single<Object> getCategoryList() {
return restApi.getCategoryList();
}
ExampleApplication.java
public class ExampleApplication extends Application {
#Inject
ApplicationComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this)).build();
appComponent.inject(this);
appComponent.plus(new UrlModule("www/test/en"));
}
public ApplicationComponent getAppComponent() {
return appComponent;
}
}
BaseActivity.java
public class BaseActivity extends AppCompatActivity {
ActivityComponent activityComponent;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//activityComponent=DaggerActivityComponent.builder().applicationModule()
activityComponent= DaggerActivityComponent.builder()
.applicationComponent(((ExampleApplication)getApplication()).getAppComponent())
.build();
}
public ActivityComponent getActivityComponent() {
return activityComponent;
}
}
MainActivity.jaqva
public class MainActivity extends BaseActivity {
#Inject
RestApiHelper restApiHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityComponent component= getActivityComponent();
component.inject(this);
restApiHelper.getquestionlist(1).subscribe(new Consumer<Object>() {
#Override
public void accept(Object o) throws Exception {
}
});
Now I have tow questions :
1-Shouldn't all the Providers built into the Urlmodule be added to ApplicationModule(UrlModule is Subcomepoent of the ApplicationComponent )
#PerActivity
#Component(modules = ActivityModule.class,dependencies = ApplicationComponent.class)
public interface ActivityComponent {
and since the ApplicationComponent is an ActivityComponent dependencies, can all of these Providers be used in the ActivityComponent as well?
2-And as a basic question, where is the problem?
Shouldn't all the Providers built into the Urlmodule be added to
ApplicationModule(UrlModule is Subcomepoent of the
ApplicationComponent )
When you declare a component dependancy then the dependant component can only use the exposed dependencies which are declared inside the component class of dependencies, in your case these are context and application in your ApplicationComponent class and provided by ApplicationModule.
For validation(testing):
1) Add a new provides in your app module
// inside ApplicationModule
#Provides
Student getNum() {
return new Student("aa");
}
2) Create and use ActivityComponent object to inject the Student in any class. It will result in missing provides. It can be fixed by exposing Student in ApplicationComponent class as:
Student getStu();
2-And as a basic question, where is the problem?
With the following implementations:
Dagger misconfigured dependancy graph, as explained above
Missing Rxjava implementation and retrofit implementations
Missing url provides etc
To fix the above follow the below steps:
Dagger misconfigured dependancy graph, as explained above
a) MainActivity requires the RestApiHelper which is provided by UrlComponent not AppComponent so first use UrlComponent as dependencies instead of AppComponent
#PerActivity
#Component(modules = ActivityModule.class, dependencies = {UrlComponent.class})
public interface ActivityComponent {
void inject(MainActivity mainActivity);
}
b) Now expose the dependancy in the UrlComponent
#PerUrl
#Subcomponent(modules = UrlModule.class)
public interface UrlComponent {
RestApiHelper getRetrofit();
}
Implementation of UrlModule.class with fixed issues(mentioned above)
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import java.util.concurrent.TimeUnit;
import dagger.Module;
import dagger.Provides;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
#Module
public class UrlModule {
private String url;
public UrlModule(String url) {
this.url = url;
}
#Provides
#PerUrl
OkHttpClient provideOkhttpClient() {
return new OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build();
}
#Provides
String provideUrl() {
return url;
}
#Provides
#PerUrl
Retrofit provideRetrofit(String baseURL, OkHttpClient client) {
return new Retrofit.Builder()
.baseUrl(baseURL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
#Provides
RestApi provideApiService(Retrofit retrofit) {
return retrofit.create(RestApi.class);
}
}
c) Build Url appComponent and urlComponent in Application class for later use as
public class ExampleApplication extends Application {
// note, I remove the inject, you were doing it for testing etc
private ApplicationComponent appComponent;
private UrlComponent urlComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this)).build();
urlComponent = appComponent.plus(new UrlModule("https://jsonplaceholder.typicode.com/"));
}
public ApplicationComponent getAppComponent() {
return appComponent;
}
public UrlComponent getUrlComponent() {
return urlComponent;
}
}
Now build the activityComponent in BaseActivity as
activityComponent= DaggerActivityComponent.builder()
.activityModule(new ActivityModule(this))
.urlComponent(((ExampleApplication)getApplication()).getUrlComponent())
.build();
and use it in your MainActivity as
public class MainActivity extends BaseActivity {
#Inject
RestApiHelper restApiHelper;
Disposable disposable;
private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityComponent component = getActivityComponent();
component.inject(this);
disposable = restApiHelper.getquestionlist(1)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
#Override
public void accept(Object o) throws Exception {
Log.d(TAG, "accept: "+ o.toString());
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
throwable.printStackTrace();
}
});
}
#Override
protected void onDestroy() {
disposable.dispose(); // best practice
super.onDestroy();
}
}
That's it.
Note: Make sure your baseUrl value and retrofit objects are properly setup and have internet app permission etc. You can optimised your code further with lambdas etc as I kept most of the code as it is for understanding.
First of all your method that provides RestApi is wrong.
I should be like
#Provides
public RestApi provideApiService(Retrofit retrofit) {
return retrofit.create(RestApi.class);
}

Dagger2: how to inject retrofit module in presenter class

Dagger2 learning is still difficult and am trying to learn. Have setup a project using new dagger android to avoid injecting inside activity class. So far it's working but need to use retrofit injected in presenter class. Added retrofit module in AppComponent but apiService class method getting null when call from presenter class. Need to know how to inject properly.
AppComponent.java
#Singleton
#Component(modules = {
/* Use AndroidInjectionModule.class if you're not using support library */
AndroidSupportInjectionModule.class,
AppModule.class,
BuildersModule.class,
RetrofitModule.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(BaseApplication application);
Builder retrofitModule(RetrofitModule retrofitModule);
AppComponent build();
}
void inject(BaseApplication app);
}
AppModule.java
#Module
class AppModule {
#Provides
Context provideContext(BaseApplication application) {
return application.getApplicationContext();
}
}
BuildersModule.java
#Module
public abstract class BuildersModule {
#ContributesAndroidInjector(modules = {SplashViewModule.class, SplashModule.class})
abstract SplashActivity bindSplashActivity();
// Add bindings for other sub-components here
}
BaseApplication.java
public class BaseApplication extends Application implements HasActivityInjector {
#Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
#Override
public void onCreate() {
super.onCreate();
//configure timber for logging
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
DaggerAppComponent
.builder()
.application(this)
.retrofitModule(new RetrofitModule())
.build()
.inject(this);
}
#Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}
RetrofitModule.java
#Module
public class RetrofitModule {
//get retrofit instance
#Singleton
#Provides
public UserAuthService getRestService() {
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiConstants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(getOkHttpClient())
.build();
return retrofit.create(UserAuthService.class);
}
}
UserAuthService.java
public interface UserAuthService {
#GET("v2/5be345062f00006b00ca22c4")
Observable<Example> getExampleResponse();
}
SplashModule.java
#Module
public class SplashModule {
#Provides
SplashPresenter provideSplashPresenter(SplashView splashView) {
return new SplashPresenter(splashView);
}
}
SplashViewModule.java
#Module
public abstract class SplashViewModule {
#Binds
abstract SplashView provideSplashView(SplashActivity splashActivity);
}
SplashPresenter.java
class SplashPresenter extends BasePresenter<SplashView> {
#Inject
#Named(ValueConstants.MAIN_THREAD)
Scheduler mMainThread;
#Inject
#Named(ValueConstants.NEW_THREAD)
Scheduler mNewThread;
#Inject
UserAuthService userAuthService;
SplashPresenter(SplashView view) {
super(view);
}
//test purpose
public void sayHello() {
userAuthService.getExampleResponse()
.observeOn(mMainThread)
.subscribeOn(mNewThread)
.subscribe(new Observer<Example>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Example example) {
Timber.d("example %s", example.toString());
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onComplete() {
}
});
}
}
here "userAuthService.getExampleResponse()" getting null. I think presenter need to know about RetrofitModule injection. So I need to fix this and how?
I would add those dependencies to the constructor of SplashPresenter and add the #Inject annotation to it. Dagger2 supports constructor injection and all the dependencies you need are resolvable (and you can also get rid of SplashModule)
class SplashPresenter extends BasePresenter<SplashView> {
private Scheduler mMainThread;
private Scheduler mNewThread;
private UserAuthService userAuthService;
#Inject
SplashPresenter(SplashView view, UserAuthService userAuthService, #Named(ValueConstants.NEW_THREAD) Scheduler newThread, #Named(ValueConstants.MAIN_THREAD) Scheduler mainThread) {
super(view);
this.userAuthService = userAuthService;
mNewThread = newThread;
mMainThread = mainThread;
}

Dagger2 Constructor Injection not working

I am trying to inject a presenter for my Fragment via Constructor injection (so that I do not need to create a #Provides method for the presenter).
I believe that I am doing it correctly, but I am still receiving the following error:
MainFragmentPresenter cannot be provided without a #Provides- or #Produces-annotation method.
Here is my setup:
ApplicationComponent.java
#Singleton
#Component(
modules = {
NetworkModule.class
}
)
public interface ApplicationComponent {
NetworkService networkService();
}
MainFragmentComponent.java
#PerFragment
#Component(
dependencies = ApplicationComponent.class,
modules = MainFragmentPresenterModule.class
)
public interface MainFragmentComponent {
MainFragmentView view();
void inject(MainFragment mainFragment);
}
MainFragmentPresenterModule.java
#Module
public class MainFragmentPresenterModule {
private final MainFragmentView _view;
public MainFragmentPresenterModule(MainFragmentView view) {
_view = view;
}
#Provides
#PerFragment
MainFragmentView provideMainFragmentView() {
return _view;
}
}
NetworkModule.java
#Module
public class NetworkModule {
#Provides
#Singleton
OkHttpClient provide_OkHttpClient() {
return new OkHttpClient();
}
#Provides
#Singleton
OpenWeatherEndpoints provide_OpenWeatherAPI(OkHttpClient client) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://api.openweathermap.org/data/2.5/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
return retrofit.create(OpenWeatherEndpoints.class);
}
#Provides
#Singleton
YoutubeEndpoints provide_YoutubeEndpoints(OkHttpClient client) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.googleapis.com/youtube/v3/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
return retrofit.create(YoutubeEndpoints.class);
}
#Provides
#Singleton
NetworkService provide_NetworkService(OpenWeatherEndpoints openWeatherEndpoints, YoutubeEndpoints youtubeEndpoints) {
return new NetworkService(openWeatherEndpoints, youtubeEndpoints);
}
}
PerFragment.java
#Scope
#Retention(RUNTIME)
#interface PerFragment {
}
MainFragmentPresenterImpl.java
public class MainFragmentPresenterImpl implements MainFragmentPresenter {
private final MainFragmentView _view;
private NetworkService _service;
#Inject MainFragmentPresenterImpl(MainFragmentView view, NetworkService networkService) {
_view = view;
_service = networkService;
}
}
And when I try to inject the presenter in my fragment...
public class MainFragment extends Fragment implements MainFragmentView {
public static final String TAG = "MainFragment";
#Inject
MainFragmentPresenter _presenter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerMainFragmentComponent.builder()
.applicationComponent(WeatherForecastApp.get(getContext()).getAppComponent())
.mainFragmentPresenterModule(new MainFragmentPresenterModule(this))
.build()
.inject(this);
}
}
All help is greatly appreciated! thanks.
You need to add a binding from MainFragmentPresenterImpl to MainFragmentPresenter. Dagger does not cast between types, so you need to do that explicitly with a #Binds method. #Binds is equivalent to a #Provides method that just returns its argument, but it's implemented more efficiently. Just change your module like this:
#Module
public abstract class MainFragmentPresenterModule {
...
#Binds
abstract MainFragmentPresenter(MainFragmentPresenterImpl impl);
}
Also, you can get rid of the #Provides method, _view field, and constructor in the module by using a #BindsInstance.
public interface MainFragmentComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder mainFragmentView(MainFragmentView mainFragmentView);
}
void inject(MainFragment mainFragment);
}
Now, since your your module doesn't have a constructor, Dagger doesn't need to be provided an instance, so you can construct the component like this:
DaggerMainFragmentComponent.builder()
.applicationComponent(WeatherForecastApp.get(getContext()).getAppComponent())
.mainFragmentView(this)
.build()
.inject(this);

Android Dagger2 error: #javax.inject.Named("BaseUrl") java.lang.String is bound multiple times

I'm trying some things with Dagger2 but still difficult to understand..
I would like to use 2 services in 2 classes, SplashActivity and HomeActivity.
Services depends on NetModule because i would like reuse retrofit and okhttpclient provides.
Here is my NetModule :
#Module
public class NetModule {
#Provides
Retrofit provideRetrofit(#Named("BaseUrl") String baseUrl, OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
#Provides
HttpLoggingInterceptor provideHttpLoggingInterceptor() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
if (BuildConfig.DEBUG) {
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
} else {
logging.setLevel(HttpLoggingInterceptor.Level.NONE);
}
return logging;
}
#Provides
OkHttpClient provideOkHttpClient(HttpLoggingInterceptor httpLoggingInterceptor, #Named("ConnectTimeoutMs") int connectTimeoutMs, #Named("ReadTimeoutMs") int readTimeoutMs) {
return new OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.connectTimeout(connectTimeoutMs, TimeUnit.MILLISECONDS)
.readTimeout(readTimeoutMs, TimeUnit.MILLISECONDS)
.build();
}
}
StaticDataModule and StatusModule, it's 2 differents API so they use NetModule :
#Module(includes = NetModule.class)
public class StaticDataModule {
#Provides
#Singleton
StaticDataService provideStaticDataService(Retrofit retrofit) {
return new RetrofitStaticDataService(retrofit);
}
#Provides
#Named("BaseUrl")
String provideBaseUrl() {
return "http://url_static.com";
}
#Provides
#Named("ConnectTimeoutMs")
int provideConnectTimeoutMs() {
return 5000;
}
#Provides
#Named("ReadTimeoutMs")
int provideReadTimeoutMs() {
return 5000;
}
}
#Module(includes = NetModule.class)
public class StatusModule {
#Provides
#Singleton
StatusService provideStatusService(Retrofit retrofit) {
return new RetrofitStatusService(retrofit);
}
#Provides
#Named("BaseUrl")
String provideBaseUrl() {
return "http://url_status.com";
}
#Provides
#Named("ConnectTimeoutMs")
int provideConnectTimeoutMs() {
return 5000;
}
#Provides
#Named("ReadTimeoutMs")
int provideReadTimeoutMs() {
return 5000;
}
}
And i build them in this component :
#Singleton
#Component(modules = {AppModule.class, StaticDataModule.class, StatusModule.class})
public interface AppComponent {
void inject(SplashActivity splashActivity);
void inject(HomeActivity homeActivity);
}
I obtain this error : #javax.inject.Named("BaseUrl") java.lang.String is bound multiple times.
I understand my error, dagger dont know who provide between StaticData baseUrl and Status baseUrl.
I tried to make 2 components, StaticDataComponent and StatusComponent, but i can't inject both in the same activity.
I tried to extends NetModule in StaticDataModule and StatusModule, and give parameters with constructor, but multiple bounds error was on retrofit provide.
So i don't know how to reuse NetModule with differents parameters in 2 modules, if someone has an example it should really help me.
Thanks !
Do not include NetModule.class as dependency to your modules, just include them separately in the component.
#Module(includes = NetModule.class)
public class StaticDataModule {
to
#Module
public class StaticDataModule {
And then use like this:
#Component(modules = {
NetModule.class, StaticDataModule.class
}) public interface FirstComponent {
void inject(WhateverYouWantActivity activity);
}
#Component(modules = {
NetModule.class, StatusModule.class
}) public interface FirstComponent {
void inject(WhateverYouWantSecondActivity activity);
}
If you have to inject into the same activity, you better rework your architecture, but if you still want to do this, you can get rid of inject method, and add something like this:
#Component(modules = { /* your modules */ }) public interface YourComponent {
Retrofit getRetrofit();
OkHttpClient getOkHttpClient();
}
And use it accordingly:
retrofit = yourComponentBuiltByDagger.getRetrofit();
Instead of:
#Inject Retrofit retrofit;
Finally i found a simple solution, my architecture was bad. Now i need only one module, and retrofit is not provide, he is build inside StaticData and Status implementation :
#Module
public class NetModule {
#Provides
HttpLoggingInterceptor provideHttpLoggingInterceptor() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
if (BuildConfig.DEBUG) {
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
} else {
logging.setLevel(HttpLoggingInterceptor.Level.NONE);
}
return logging;
}
#Provides
OkHttpClient provideOkHttpClient(HttpLoggingInterceptor httpLoggingInterceptor) {
return new OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.connectTimeout(5000, TimeUnit.MILLISECONDS)
.readTimeout(5000, TimeUnit.MILLISECONDS)
.build();
}
#Provides
#Singleton
StaticDataService provideStaticDataService(OkHttpClient okHttpClient) {
return new RetrofitStaticDataService("http://url_1.com",okHttpClient);
}
#Provides
#Singleton
StatusService provideStatusService(OkHttpClient okHttpClient) {
return new RetrofitStatusService("http://url_2.com",okHttpClient);
}
}
#Singleton
#Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {
void inject(SplashActivity splashActivity);
void inject(HomeActivity homeActivity);
}
Retrofit objects are only in retrofit implementation class, so if i need change retrofit by another library i have just to change new RetrofitStaticDataService() by new AnotherStaticDataService().
Thanks for help Anton.

Component depends on more than one scoped component?

I am using dagger 2 in my App. And now i am continuously facing this below error.
Error:(14, 1) error: #com.example.hp.daggerdemoexample.scope.UserScope com.example.hp.daggerdemoexample.component.ServerComponent depends on more than one scoped component:
#Singleton com.example.hp.daggerdemoexample.component.NetworkComponent
#Singleton com.example.hp.daggerdemoexample.component.DatabaseManagerComponent
Below is my Component Classes
ServerComponent.java
#UserScope
#Component(dependencies = {NetworkComponent.class, DatabaseManagerComponent.class}, modules = ServerModule.class)
public interface ServerComponent extends NetworkComponent, DatabaseManagerComponent {
void inject(MainActivity mainActivity);
void inject(RecyclerViewFragment mainActivity);
}
NetworkComponent.java
#Singleton
#Component (modules={ApplicationModule.class, NetworkCallModule.class})
public interface NetworkComponent {
Retrofit retrofit();
OkHttpClient okHttpClient();
}
DatabaseManagerComponent.java
#Singleton
#Component (modules = DatabaseManagerModule.class)
public interface DatabaseManagerComponent {
DBFlowHelper dbFLow();
}
UserScope.java
#Scope
public #interface UserScope {
}
And ApplicationData Class
ApplicationData.java
public class ApplicationData extends Application {
private NetworkComponent mNetComponent;
private ServerComponent mServerComponent;
private DatabaseManagerComponent mDatabaseManagerComponent;
#Override
public void onCreate() {
super.onCreate();
FlowManager.init(this);
mNetComponent = DaggerNetworkComponent.builder()
.applicationModule(new ApplicationModule(this))
.networkCallModule(new NetworkCallModule("https:XXXXXXXX"))
.build();
mDatabaseManagerComponent = DaggerDatabaseManagerComponent.builder()
.databaseManagerModule(new DatabaseManagerModule())
.build();
mServerComponent = DaggerServerComponent.builder()//Error in this line due to ServerComponent Class DaggerServerComponent
.networkComponent(mNetComponent)
.databaseManagerComponent(mDatabaseManagerComponent)
.serverModule(new ServerModule())
.build();
}
public DatabaseManagerComponent getDatabaseManagerComponent(){
return mDatabaseManagerComponent;
}
public NetworkComponent getNetworkComponent(){
return mNetComponent;
}
public ServerComponent getServerComponent(){
return mServerComponent;
}
}
Help me any one how to fix this issue.
Thanks in Advance

Categories