Dagger 2 LocalDataSource cannot be provided without #Provides annotated method - java

I'm trying to follow the same example as in here by creating a Repository pattern with DI.
The problem is that I get the following error:
"Error:(16, 20) error: #mvp.model.di.scope.Local
mvp.model.repository.local.GameLocalDataSource cannot be provided
without an #Provides-annotated method. #mvp.model.di.scope.Local
mvp.model.repository.local.GameLocalDataSource is injected at
mvp.model.repository.GameRepository.(gameLocalDataSource, …)
mvp.model.repository.GameRepository is provided at
mvp.model.di.component.RepositoryComponent.getGameRepository()"
Here's the code related to the app:
public class GameApplication extends Application {
private RepositoryComponent repositoryComponent;
#Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
// Normal app init code...
repositoryComponent = DaggerRepositoryComponent.builder()
.applicationModule(new ApplicationModule((getApplicationContext())))
.build();
}
public RepositoryComponent getRepositoryComponent() {
return repositoryComponent;
}
}
This is my RepositoryComponent:
#Singleton
#Component(modules = {RepositoryModule.class, ApplicationModule.class})
public interface RepositoryComponent {
GameRepository getGameRepository();
}
Here's the RepositoryModule:
#Module
public class RepositoryModule {
#Singleton
#Provides
#Local
GameDataSource provideLocalDataSource(Context context) {
return new GameLocalDataSource(context);
}
#Singleton
#Provides
#Remote
GameDataSource provideRemoteDataSource() {
return new GameRemoteDataSource();
}
}
And finally, the ApplicationModule:
#Module
public final class ApplicationModule {
private Context context;
public ApplicationModule(Context context) {
this.context = context;
}
#Provides
Context providesContext() {
return context;
}
}
Here's most of my GameRepository class:
#Singleton
public class GameRepository implements GameDataSource {
private GameDataSource remoteDataSource;
private GameDataSource localDataSource;
#Inject
public GameRepository(#Local GameLocalDataSource gameLocalDataSource, #Remote GameRemoteDataSource gameRemoteDataSource) {
remoteDataSource = gameRemoteDataSource;
localDataSource = gameLocalDataSource;
}
Also, as in the mentioned example, I created a couple of scopes, #Local and #Remote since my two data sources have the same type and Dagger needs to differentiate them.
#Qualifier
#Documented
#Retention(RetentionPolicy.RUNTIME)
public #interface Local {
}
The rest of the code I have related to dagger, is just the #Inject in the constructors where I want to inject my dependencies.
Also, the DaggerRepositoryComponent is never generated in the GameApplication class.
Thanks a lot for the help in advance!

GameLocalDataSource cannot be provided without an #Provides-annotated method
Somewhere in the code you are trying to #Inject GameLocalDataSource, but you have specified in your module how to provide GameDataSource, not GameLocalDataSource.
...
GameDataSource provideLocalDataSource(Context context) {
return new GameLocalDataSource(context);
}
...
Either ask Dagger to inject GameDataSource, or describe Dagger how to provide GameLocalDataSource.
...
GameLocalDataSource provideLocalDataSource(Context context) {
return new GameLocalDataSource(context);
}
...

Related

Dagger2 Android Depedency injection java

i'm new to dagger2.
I'm trying to create an 'ActivityComponent' which will retrieves all information from my activity (ex : context ...), and an another component in which i'm trying to inject the 'Activity component' (in the code below, it's the CheckErrorsModel class).
#Singleton
public class CheckErrorsModel {
private Context context;
#Inject
public CheckErrorsModel(MainActivityComponent mainActivityComponent) {
this.context = mainActivityComponent.getContext();
}
public void test() {
Log.d("test", "test lancé ");
}
}
The Interface component class :
#Singleton
#Component()
public interface CheckErrorsModelDi {
CheckErrorsModel getCheckErrorsModel();
MainActivityComponent getApplicationComponent();
}
And everything related to the Application context class :
#Component(modules = {MainActivityModule.class})
#Singleton
public interface MainActivityComponent {
Context getContext();
void inject(MainActivity mainActivity);
}
the module class :
#Module
public class MainActivityModule {
private final Context context;
public MainActivityModule(Context context) {
this.context = context;
}
#Provides
#Singleton
Context provideContext(){
return context;
}
}
But once i try to build the app :
i got some errors :
.MainActivityComponent cannot be provided without an #Provides-annotated method MainActivityComponent getApplicationComponent();
MainActivityComponent cannot be provided without an #Provides-annotated method.
CheckErrorsModel getCheckErrorsModel()
I think this is because your CheckErrorsModelDi don't have any module.
And Scope (like #Singleton) should always be on Module method and the component
And this should be a subComponent of MainActivityComponent
Alors you inject Method seems à bit strange.
You should use à builder instead see bindings instance

Using AndroidInjections contribution module (abstract class) as subcomponent in Dagger 2

I study Dagger 2 and try to understand how I can attach it to an already existing project. Now I faced with the following problem with injectiing dependencies into BroadcastReceivers. I can't use DaggerReceiver because my receivers already extends another class. To use AndroidInjection inside BroadcastReceivers, I should inject DispatchingAndroidInjector to Application class. I don't want to include module with AndroidInjection contributors to main dependency graph so, how I understand, I should place it to dedicated component for Application class, but because of this duplication of Singletons occurs.
Here is my example (GitHub repo)
Classes to provide dependencies to MainActivity and other classes
AppModule.class
#Module
public class AppModule {
Application mApplication;
public AppModule(Application application) {
mApplication = application;
}
#Singleton
#Provides
Application providesApplication() {
return mApplication;
}
}
UtilityModule.class
#Module
public class UtilityModule {
#Singleton
#Provides
FirstUtilityClass providesFirstUtility(Application app) {
return new FirstUtilityClass(app);
}
#Singleton
#Provides
SecondUtilityClass providesSecondUtility(Application app) {
return new SecondUtilityClass(app);
}
}
MainComponent.class
#Singleton
#Component(modules = { AppModule.class, UtilityModule.class })
public interface MainComponent {
void inject(MainActivity activity);
}
Classes to provide DispatchingAndroidInjector to Application class
ReceiversModule.class
#Module
public abstract class ReceiversModule {
#ContributesAndroidInjector
abstract FirstReceiver contributesFirstReceiver();
#ContributesAndroidInjector
abstract SecondReceiver contributesSecondReceiver();
}
ReceiversComponent.class
#Singleton
#Component(modules = { AppModule.class, UtilityModule.class, ReceiversModule.class })
public interface ReceiversComponent {
void inject(MyApplication application);
}
Injecting...
MyApplication.class
public class MyApplication extends Application implements HasBroadcastReceiverInjector {
#Inject DispatchingAndroidInjector<BroadcastReceiver> mInjector;
#Inject FirstUtilityClass mFirstUtility;
#Inject SecondUtilityClass mSecondUtility;
MainComponent mMainComponent;
#Override
public void onCreate() {
AppModule appModule = new AppModule(this);
mMainComponent = DaggerMainComponent.builder().appModule(appModule).build();
// I should build new component only for Application class, because DispatchingAndroidInjector not required for another targets
DaggerReceiversComponent.builder().appModule(appModule).build().inject(this); // Here created new scope
super.onCreate();
// do something
mFirstUtility.doFistThings(getClass().getSimpleName());
mSecondUtility.doSecondThings(getClass().getSimpleName());
}
public MainComponent getMainComponent() {
return mMainComponent;
}
#Override
public AndroidInjector<BroadcastReceiver> broadcastReceiverInjector() {
return mInjector;
}
}
MainActivity.class
public class MainActivity extends AppCompatActivity {
#Inject FirstUtilityClass mFirstUtility;
#Inject SecondUtilityClass mSecondUtility;
#Override
protected void onCreate(Bundle savedInstanceState) {
((MyApplication) getApplication()).getMainComponent().inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Do something
mFirstUtility.doFistThings(getClass().getSimpleName());
mSecondUtility.doSecondThings(getClass().getSimpleName());
// Sending broadcasts here
}
}
Logcat output
FirstUtilityClass1: doing first things from MyApplication...
SecondUtilityClass1: doing second things from MyApplication...
FirstUtilityClass2: doing first things from MainActivity...
SecondUtilityClass2: doing second things from MainActivity...
FirstUtilityClass1: doing first things from FirstReceiver...
SecondUtilityClass1: doing second things from SecondReceiver...
How you see in log, Apllication and MainActivity receives different instances of utility classes. I had an idea to make ReceiversComponent as a subcomponent of MainComponent. But ReceiversModule is abstract and I cant add it dinamicaly to existed component instance.
MainComponent.class
#Singleton
#Component(modules = { AppModule.class, UtilityModule.class })
public interface MainComponent {
ReceiversComponent with(ReceiversModule module);
void inject(MainActivity activity);
}
ReceiversComponent.class
#Subcomponent(modules = { ReceiversModule.class })
public interface ReceiversComponent {
void inject(MyApplication application);
}
And then in MyApplication:
// It does not work because I can't create ReceiverModule instance :(
mMainComponent.with(new ReceiversModule()).inject(this);
How can I use the ReceiversComponent as a subcomponent of MainComponent?
It's clear to me that I'm doing something wrong, but I just can't understand where. Maybe there is another way to solve my problem?
I just found the answer!
Since my ReceiversModule class has a default constructor without parameters, I can skip it as parameter when describing the subcomponent in MainComponent interface:
MainComponent.class
#Singleton
#Component(modules = { AppModule.class, UtilityModule.class })
public interface MainComponent {
ReceiversComponent withReceiversModule(); // Here is the reference to the subcomponent with abstract module
void inject(MainActivity activity);
}
MyApplication.class
#Override
public void onCreate() {
AppModule appModule = new AppModule(this);
mMainComponent = DaggerMainComponent.builder().appModule(appModule).build();
mMainComponent.withReceiversModule().inject(this); // It's works!!! :)
super.onCreate();
// do something
mFirstUtility.doFistThings(getClass().getSimpleName());
mSecondUtility.doSecondThings(getClass().getSimpleName());
}
Maybe someone will think it is a trifle, but it took me several days to reach it. I'm very happy, because my code has become a little cleaner. Thanks to all!

One dependency in multiple services classes with Dagger 2

I want to inject a custom class as an dependency in different service classes, but I don't get it work. It always ends with a NPE. Here is my example (simple Java SE) ...
My Main class to get everything running
public class Main {
public static void main(String[] args) throws IOException, TimeoutException {
MyApplication MyApp = new MyApplication();
MyApp.execute();
}
}
MyApplication class
public class MyApplication {
private MyApplicationComponent appComponent;
#Inject FooService fooService;
#Inject BarService barService;
#Inject BazService bazService;
public MyApplication() {
component = DaggerMyApplicationComponent.builder().build();
component.inject(this);
}
public void execute() {
fooService.doStuff();
barService.doStuff();
// this will happen in the FooService construct, see below
// bazService.doStuff();
}
}
Component and Module classes as defined in Dagger, without using it the #Inject constructor way
#Singleton
#Component(modules = {MyApplicationModule.class})
public interface MyApplicationComponent {
void inject(MyApplication application);
}
#Module
public class MyApplicationModule {
#Singleton
#Provides
FooService provideFooService() {
return new FooService();
}
#Singleton
#Provides
BarService provideBarService() {
return new BarService();
}
#Provides
BazService provideBazService() {
return new BarService();
}
}
Using the MyApplicationModule and MyApplicationComponent to provide needed dependencies works within the Main.class. I also want to use the BazService within the FooService class. Therefore I use the #Inject way to define it as a dependency with FooService.class.
Using #Inject of BazService within the FooService.class
public class FooService {
#Inject BazService bazService;
public FooService(){}
public doStuff(){
bazService.doStuff();
}
}
Running the Main.class always ends within a NPE, due to undefined bazService in the FooSerivce class. I don't think, that I missed to add an annotation anywhere. I think Dagger will not work this way ... any ideas?
FooService expects bazService to be injected though field injection but you are calling bazService before this happens. If you want to call bazService.doStuff() in FooService's constructor you'll have to use constructor injection.

Dagger dependency injection to service fails with "contactServiceModule must be set at DaggerAppComponent$Builder.build(DaggerAppComponent.java)"

I am using dagger for dependency injection, I apologize for not diving into deep and getting my hands on :)
I am using two modules(ApplicationModule, ContactServiceModule), with a component (AppComponent). I have initialized the Dagger in App.java, and I am trying to inject dependencies to a backgroud Service.
Here is the code snippet.
1)ApplicationModule.java
#Module
public class ApplicationModule {
private final App mApp;
private Service contactService;
public ApplicationModule(App app) {
mApp = app;
}
#Provides
#Singleton
public ContactModel contactModel(SQLiteDatabase database) {
return new ContactModel(mApp, database);
}
#Provides
#Singleton
public Context appContext() {
return mApp;
}
#Provides
#Singleton
public ContactController contactController() {
return new ContactController(mApp.getAppComponent());
}
//.....Some more code
}
2)ContactServiceModule.java
#Module
public class ContactServiceModule {
ContactService contactService;
public ContactServiceModule(ContactService contactService){
this.contactService =contactService;
}
#Provides
#Singleton
ContactService provideContactService() {
return this.contactService;
}
}
3)AppComponent.java
#Singleton
#Component(modules = {ApplicationModule.class,ContactServiceModule.class})
public interface AppComponent {
ContactController contactController();
Context appContext();
//...Some code
void inject(ContactController contactController);
//...Some code
void inject(ContactService contactService);
}
4)App.java
public class App extends Application {
private AppComponent mAppComponent;
#Override
public void onCreate() {
super.onCreate();
FlowManager.init(this);
mAppComponent = DaggerAppComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
}
public AppComponent getAppComponent() {
return mAppComponent;
}
}
5) ContactService.java
public class ContactService extends Service {
#Inject
Context appContext;
#Inject
ContactController contactController;
#Override
public void onCreate() {
super.onCreate();
getAppComponent().inject(this);
}
private AppComponent getAppComponent() {
return ((App)getApplication()).getAppComponent();
}
}
It could be an issue of dependencies of UI threads injected into background services. But I do not understand how should I achieve the same dependencies to be injected into services. Or what should be the Ideal way to communicate between application level dependencies and services. I want the service to be running always in the background and listening to various intents and also communicate to other dependencies like eventbus etc.
The error message:
contactServiceModule must be set at DaggerAppComponent$Builder.build(DaggerAppComponent.java)”
means that you have created a module with dependencies in the constructor (ContactServiceModule which has your Service as a parameter in the constructor). It follows that Dagger 2 cannot instantiate that module automatically and it must be instantiated in the builder when you create your component:
mAppComponent = DaggerAppComponent.builder()
.applicationModule(new ApplicationModule(this))
.contactServiceModule(contactService);
.build();
However there is an underlying issue with the architecture you are trying to create. Services, like Activities, are designed to be autonomous and instantiated by the Android OS. Much in the same way you wouldn't directly pass as an Activity as a dependency to another Activity, you shouldn't make a Service a dependency. Instead you need to use Intent, service binding, or EventBus events to communicate with the service. The Android Service documentation covers this and you should read it carefully before proceeding.

Dagger 2 single instance of MyClass

I'm trying to refactor my code so I was thinking about Dagger2 to solve my issues. I've created AppComponent to store all of my Singletons:
#AppScope
#Component(
modules = {
AppModule.class,
// more here...
}
)
public interface AppComponent {
Context exposeContext();
CmdComponent newCmdComponent(CmdModule module);
// ... few injections here
}
My AppModule:
#Module
public class AppModule {
private Context context;
public AppModule(Context context) {
this.context = context;
}
// ... provide appContext etc.
#AppScope #Provides
MyClass provideMyClass() {
Log.i("DAGGER", "provideMyClass: ");
return new MyClass();
}
}
I inject this in my Application class:
public class App extends Application {
private static AppComponent component;
#Override
public void onCreate() {
super.onCreate();
component = DaggerAppComponent.builder()
.appModule(new AppModule(app))
.build();
}
public static AppComponent getAppComponent() {
return component;
}
}
Then I have my subcomponent CmdComponent with different #Scope
#CmdScope
#Subcomponent(
modules = {
CmdModule.class
}
)
public interface CmdComponent {
void inject(Cmd cmd);
}
Now I'm injecting dependancies into my Cmd instance like:
#Inject MyClass myClass;
public Cmd() {
App.getAppComponent()
.newCmdComponent(new CmdModule())
.inject(this);
}
Unfortunetly log: Log.i("DAGGER", "provideMyClass: "); and log inside MyClass constructor are shown multiple times... so I get new instance of MyClass every time. How to tell Dagger to give me the same instance (created once) every time?
Ok. I solve my issue. The solution is simple. My AppScope was created wrong. For some reason, I thought that annotation works like inheritance.
My custom annotation was like:
#Singleton
#Retention(RetentionPolicy.RUNTIME)
public #interface AppScope {
}
and Dagger thought that my component is unscoped.. It should be like:
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface AppScope {
}
How about the .newCmdComponent(new CmdModule()). Why do you do that, creating a new module every time? The component already has a module attached, you've set that on creation of the component.

Categories