Dagger 2.2 component builder module method deprecated - android

I started using dagger 2.2 and the module methods in the Component builder are deprecated.
This is my Application component :
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(Application application);
}
And the Application module:
#Module
public class ApplicationModule {
Application application;
public ApplicationModule(Application application) {
this.application = application;
}
#Provides
#Singleton
Application providesApplication() {
return application;
}
}
Here is the generated class:
#Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerApplicationComponent implements ApplicationComponent {
private DaggerApplicationComponent(Builder builder) {
assert builder != null;
}
public static Builder builder() {
return new Builder();
}
public static ApplicationComponent create() {
return builder().build();
}
#Override
public void inject(Application application) {
MembersInjectors.<Application>noOp().injectMembers(application);
}
public static final class Builder {
private Builder() {}
public ApplicationComponent build() {
return new DaggerApplicationComponent(this);
}
/**
* #deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
*/
#Deprecated
public Builder applicationModule(ApplicationModule applicationModule) {
Preconditions.checkNotNull(applicationModule);
return this;
}
}
}
How do I initialize the component if not with the ComponentBuilder?

You should read the description of why it is deprecated. If you are using an IDE like IntelliJ or Android Studio you can just select the method and hit Control + Q on Windows to read the Javadoc including the deprecation notice.
The Javadoc reads:
#deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
And from this link you can see:
When the Dagger processor generates components, it only requires instances of modules and component dependencies that are explicitly needed to supply requests for a binding.
If all of a module’s methods that are used in the component are static, Dagger does not need an instance of that module at all. Dagger can invoke the static methods directly without a module.
If a module provides no bindings for a Component, no instance of that module is necessary to construct the graph.
It is safe to say that you can just ignore the deprecation. It is intended to notify you of unused methods and modules. As soon as you actually require / use Application somewhere in your subgraph the module is going to be needed, and the deprecation warning will go away.

It show deprecated because you are not using Component and module in your application by
#Inject
SomeObjectFromModule mSomeObject
if you are not injecting dependencies in your applications there is no use of initialising your component so dagger look for at least one usage
once you add these lines in any classes you want to inject views and then clean build and rebuild the project and your deprecation will be solved

It showing error when my Module have no #Provides method or the object that provide by Dagger is not used in app.
Example to remove deprecated module
Module
#Module
public class SecondActivityModule {
#Provides
Book provideBookTest() {
return new Book();
}
}
Activity
public class SecondActivity extends AppCompatActivity {
#Inject
Book test;
...
}
OR in Component
#Component(modules = SecondModule.class)
public interface SecondComponent {
void inject(SecondActivity activity);
Book getBookTest();
}

I have the same problem with host and I just want everyone has deprecated issue on Generated component builder class should check two things to save time:
1/ Correct dagger syntax for module, component also check carefully where you inject.
2/ Must have injection object (inject annotation and its object) in place you want to inject or else the dagger compiler cannot see where to use your module so some method will be deprecated.Just inject at least one module's provides to your injection place and re-compile the code, you won't have that issue anymore :)

you will get module method deprecated if you declare void inject(AppCompactActivity activity); in component class. instead of you have to use tight coupling like following void inject(MainActivity activity);and rebuild your project you will see, there is no deprecate method in module class

Related

Dagger2: Component cannot depend on multiple scoped components

Yes, I know this has been asked before, and yes, I know it is "by design".
But I'd like to do something like this:
#Component(modules = {RealmModule.class})
public interface RealmComponent {
Realm realm();
}
#Component(modules = {RepositoryModule.class})
public interface RepositoryComponent {
PersonRepository personRepository();
ScheduleRepository schedulesRepository();
}
#Component(dependencies = {RealmComponent.class, RepositoryComponent.class})
public interface AppDataComponent
extends RealmComponent, RepositoryComponent {
}
#ApplicationScope
#Component(dependencies = {AppContextComponent.class,
AppDataComponent.class,
AppDomainComponent.class,
AppPresentationComponent.class,
AppUtilsComponent.class})
public interface ApplicationComponent
extends AppContextComponent, AppDataComponent, AppDomainComponent, AppUtilsComponent, AppPresentationComponent {
void inject(CustomApplication customApplication);
void inject(DashboardActivity dashboardActivity);
}
However, what I get is unscoped, every time I inject a JobManager or a ScheduleRepository or anything else, I get a new instance. The only way I could "fix" that was this.
#Module
public class JobManagerModule {
private JobManager jobManager;
#Provides
public JobManager jobManager(Context context) {
if(jobManager == null) {
jobManager = new JobManager(context, new Configuration.Builder(context).networkUtil(
new WifiOrMobileNetworkUtil(context)).build());
}
return jobManager;
}
}
Not a fan.
So, how is one meant to structure and rip apart the dependency tree, without making one big gigantic über blob component that has every single module listed and every single provision method (instead of these "subcomponent" component dependencies)?
I tried using subcomponents for this, but then you have to provide every single module for the final ApplicationComponent.
I'm not sure what to do here. I tried specifying #Singleton for every first-level component and #SubcomponentScope for every AppDataLevelComponent, I also tried making a new scope for every single subcomponent, but both of them failed with "cannot depend on multiple scoped components".
EDIT: Apparently in order to get scoped providers, marking the components with the scope is not enough - you must specify the scope for the #Provides annotated methods too.
#Module
public class RepositoryModule {
#Provides
#Singleton
public PersonRepository personRepository() {
return new PersonRepositoryImpl();
}
#Provides
#Singleton
public ScheduleRepository schedulesRepository() {
return new SchedulesRepositoryImpl();
}
}
In the meantime, I ended up with this übercomponent.
#Singleton
#Component(modules = {
AppContextModule.class,
DbMapperModule.class,
DbTaskModule.class,
RealmModule.class,
RepositoryModule.class,
InteractorModule.class,
ServiceModule.class,
PresenterModule.class,
XmlPersisterModule.class
})
public interface ApplicationComponent
extends AppContextComponent, AppDataComponent, AppDomainComponent, AppUtilsComponent, AppPresentationComponent {
Where the xyzComponent classes are just interfaces to store the provision methods...
(Please note that this structure is an anti-pattern as described by Martin Fowler, and you should organize modules based on features / activities, and make them into subscoped components using component dependencies. Component dependencies are used to subscope your superscope components, and "inherit" dependency providers.)
I had same problems like you not while ago and ended using the same ubercomponent approach except I use #Subcomponents in order organize the things and not to have all modules listed in the ubercomponent (I call it "top" or "app's" component).
You may see an example here:
How to migrate missing inject from module with complete = false from Dagger 1 to Dagger 2

Dagger2: Make parent component dependency accessible for subscoped component

I have the following setup:
#ApplicationScope
#Component(
dependencies = {AppContextComponent.class, CertUtilsComponent.class, ServiceComponent.class, JobManagerComponent.class})
public interface ApplicationComponent
extends AppContextComponent, CertUtilsComponent, ServiceComponent, JobManagerComponent {
void inject(MainActivity mainActivity); //honestly, I won't need this
}
And I have the following subscoped component:
#PresenterScope
#Component(dependencies = {ApplicationComponent.class, PersistenceComponent.class})
public interface PresenterComponent
extends ApplicationComponent, PersistenceComponent {
void inject(HomePresenter homePresenter);
void inject(SendCertificateRequestInteractor sendCertificateRequestInteractor);
}
The problem is that PersistenceComponent has the following component as its dependency:
#Component(dependencies = {JobManagerComponent.class, RealmComponent.class, RepositoryComponent.class}, modules = {PersisterModule.class})
public interface PersisterComponent {
DummyCertPersister dummyCertPersister();
}
Which uses JobManagerComponent, which is the dependency of the ApplicationComponent.
Unfortunately, this component does not seem to be inherited from ApplicationComponent. I need to explicitly keep track of this component, and provide it for the builder like so.
//INJECTOR
ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
.appContextComponent(appContextComponent)
.certUtilsComponent(certUtilsComponent)
.jobManagerComponent(jobManagerComponent)
.serviceComponent(serviceComponent)
.build();
this.jobManagerComponent = jobManagerComponent;
this.applicationComponent = applicationComponent;
this.certUtilsComponent = certUtilsComponent;
this.appContextComponent = appContextComponent;
this.serviceComponent = serviceComponent;
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
public JobManagerComponent getJobManagerComponent() {
return jobManagerComponent;
}
And provide this through a getter when I build my persistence component:
PersisterComponent persisterComponent = DaggerPersisterComponent.builder()
.jobManagerComponent(Injector.INSTANCE.getJobManagerComponent()) //this should be subcomponent
.realmComponent(realmComponent)
.repositoryComponent(repositoryComponent)
.persisterModule(new PersisterModule())
.build();
I would like to have that JobManagerComponent inherited from ApplicationComponent. I'm guessing I need to make this into a #Subcomponent and provide a provision method for it, but so far, it hasn't worked (I don't get a builder method, but it still doesn't see the jobManager within JobManagerComponent.
Is this possible with #Subcomponent? Or do I need to keep track of the "subcomponents" of ApplicationComponent in case a child component depends on it?
The answer is that I was conceptually wrong about how Components work in Dagger2.
A component should only depend on another component if it subscopes that component. A component with multiple component dependencies cannot depend on scoped components; which means they cannot have scoped modules; which also means they cannot use scopes at all and unless the module keeps a reference to the new instance, you'll get a new instance each time you inject. Which is bad, and not what you want at all.
The proper way is to bind every module of the same scope to the same component. That way, the provided dependencies are accessible within the constructors, and you won't have an issue with sharing the same module within different components as well.
Therefore, the approach in the question is completely wrong.
Use this instead.

how can I inject a dependency in a method?

I'm a beginner with dependency injection.. specifically Dagger 2. I'm trying to figure out if/how I can do something like this:
#Inject
public void someMethodName(int someInteger, SomeObject dependency){
// do something with the dependency.
}
Or do I need to put that dependency in as a class var? any help with this would be greatly appreciated. also in this case the variable someInteger is not a dependency, but is being added by the caller... does that matter?
can I call it like this:
this.someMethodName(5);
android studio does not like the above calling method (I'm assuming because I'm doing something wrong)
You need to create component which is annotated by #Component.
The Component accepts module which provides dependencies.
Every component's name that you create starts with Dagger prefix, e.g. for MyComponent.
Let's look at the following example:
#Singleton
#Component(modules = DemoApplicationModule.class)
public interface ApplicationComponent {
void inject(DemoApplication application);
}
We created ApplicationComponent with single injection method. What we're saying is that we want to inject certain dependencies in DemoApplication.
Moreover, in the #Component annotations we specify module with provision methods.
This is like our module looks like:
#Module
public class DemoApplicationModule {
private final Application application;
public DemoApplicationModule(Application application) {
this.application = application;
}
#Provides #Singleton SomeIntegerHandler provideIntegerHandler() {
return new MySomeIntegerHandlerImpl();
}
}
What we're saying by creating DemoApplicationModule is that the module can provide desired dependencies in the injection place specified by our Component.
public class DemoApplication extends Application {
private ApplicationComponent applicationComponent;
#Inject SomeIntegerHandler handler;
#Override public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent.builder()
.demoApplicationModule(new DemoApplicationModule(this))
.build();
applicationComponent.inject(this);
handler.someMethodName(5);
}
}
See documentation what you kind of dependencies you can obtain. Additionally to obtaining just raw instance you can obtain Provider, Factory or Lazy instance.
http://google.github.io/dagger/api/latest/dagger/Component.html
You can also create scoped dependencis, the lifecycles of which depend on the lifecycle of injection places, like Activities or Fragments.
Hope I gave you the basic notion of what Dagger is.
YOU CAN USE SOME INTERFACE
public interface myDependence{
int myFunction(int value);
}
NOW IMPLEMENT IN YOU CLASS
public myClass implements MyDependence{
#Override
int myFunction(int value){
// do something
}
}

What does #Module means in dagger for android?

I have read many blogs but still i am not able to figure out #Module annotation functioning in dagger.
#Inject i got that it provides dependency injection at runtime. But what does #Module does.
since the object graph is also built on module.
For ex i.e i have this snippet of code from https://github.com/AndroidBootstrap/android-bootstrap.
#Module(
complete = false,
injects = {
BootstrapApplication.class,
BootstrapAuthenticatorActivity.class,
MainActivity.class,
BootstrapTimerActivity.class,
}
)
public class BootstrapModule {
}
so what does it basically does. since i am also trying to build one application using dagger as dependency injection for android.But since I am not able to get #Module concept clearly I am just stuck.
Can anyone please help me out with some basic example or concept. I think this will be helpful for all who is using dagger.
If you have a look to the docs for the annotation, a #Module annotated class defines a class that contributes to the dagger object graph. In the Spring framework for example, the equivalent would be the #Configuration anntotation. It defines a configuration point for your object graph, where you declare which objects you want to be available for injection and their scopes.
As a simple example, let's say we want a singleton object to be used by any Activity in the app. It has to be created in the module:
#dagger.Module(injects = {MyActivity.class})
public class Module {
#Provides
#Singleton
public MySinletonBean provideMySingleton() {
return new MySinletonBean();
}
}
This will create a MySingleton object which can be injected in MyActivity. This is a very basic example, but we can perform other actions in the graph there, like using dependencies in the constructors:
#dagger.Module(injects = {MyActivity.class})
public class Module {
private DependencyBean dependency = new DependencyBean();
#Provides
#Singleton
public MySinletonBean provideMySingleton() {
return new MySinletonBean(dependency);
}
#Provides
#Singleton
public MySinletonBean provideMyOtherSingleton() {
return new MyOtherSinletonBean(dependency);
}
}
Then, in MyActivity we need to access the graph for the application in the onCreate method:
#Inject
MySingletonBean singleton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
((MyApplication) getApplication()).getGraph().inject(this);
}
So, who does create the object graph here? The MyApplication class does it when your application starts (don't forger to add it in your androidManifest.xml):
public class MyApplication extends Application {
private ObjectGraph graph;
public ObjectGraph getGraph() {
return graph;
}
#Override
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(new Module(this));
graph.inject(this);
}
}
So the execution flow in a dagger app would be:
The android app starts and the MyApplication class builds the graph, parsing the #Module annotated classes and keeping an instance of it.
Then, the classes declared in the module can access its objects just injecting themselves in the object graph. Gradle then will evaluate their #Inject annotations and perform the dependency injections.
I guess Annotation Processing Tool requires that to generate code at the compile time.
This makes it Dagger can provide validation at compile time and not only at runtime.

Dagger not injecting Android Annotations class

Alright, I'm having an issue trying to mix frameworks.
So, I have a #SharedPref annotated class that should generate a Shared Preferences manager from Android Annotations. The class looks a bit something like this:
DownloadPrefs.java
#SharedPref(value= SharedPref.Scope.UNIQUE)
public interface DownloadPrefs {
#DefaultBoolean(false)
boolean hasEnabledDownload();
#DefaultBoolean(false)
boolean showedDownloadDialog();
#DefaultLong(0)
long downloadRefreshedOn();
}
Now, I'd like to inject the resulting class (which will be DownloadPrefs_) into a Fragment to make use of it. The fragment has had working injection before adding the new module, so I'm only going to write here what I added:
Fragment.java
#Inject DownloadPrefs_ downloadPrefs;
Now, since the actual DownloadPrefs_ class is generated at runtime, it would make the most sense to create an #Provides annotation for it, since I can't mark a constructor as injected. Nor does the DownloadPrefs_ have a no-arg constructor. The module I'm using then receives the new #Provides:
DownloaderModule.java
#Provides //#Singleton // Does not work with/out #Singleton
DownloadPrefs_ provideDownloadPrefs() {
return new DownloadPrefs_(MinimalBible.getApplication());
}
To be technical about it, the DownloadPrefs_ constructor that gets generated by Android Annotations expects a Context passed to it, I would have guessed that the Application context would be suitable. Otherwise, I'm not sure how I could possibly get access to the Activity context. Or whether that would actually break the ObjectGraph.
However, when I go to run the actual injection, I get the following message:
Caused by: java.lang.IllegalStateException: Errors creating object graph:
org.bspeice.minimalbible.activities.downloader.DownloadPrefs_ has no injectable members. Do you want to add an injectable constructor? required by class org.bspeice.minimalbible.activities.downloader.BookListFragment
Any clue on what's going on? It doesn't seem like the questions asking about "no injectable members" on other SO questions answered my case. I had a working app before adding the code above.
UPDATE: After doing some double-checking, I came across the following weird behavior. If I copy out the pre-built Android Annotations class, rename it, and inject that, everything works. Additionally, I can verify that the original built Android Annotations class (the DownloadPrefs_.java) does in fact exist in the .dex, so Dagger should have no reason to not be able to find it. Everything is doing a debug build, so I can't imagine ProGuard is messing anything up.
At this point, I'm going to create a minimal project to demonstrate the error, and file an issue with Dagger. In the mean time, just need to rewrite the Prefs class until I can get this sorted out.
UPDATE 5/12/2014
Here are the modules responsible for injection:
MinimalBibleModules.java
#Module(
injects = {
MinimalBible.class
},
includes = {
ActivityModules.class
}
)
public class MinimalBibleModules {
}
ActivityModules.java
#Module(
includes = {
ActivityDownloaderModule.class
}
)
public class ActivityModules {
}
ActivityDownloaderModule.java
#Module(
injects = {
BookListFragment.class,
DownloadManager.class,
BookRefreshTask.class
}
)
public class ActivityDownloaderModule {
#Provides #Singleton
DownloadManager provideDownloadManager() {
return new DownloadManager();
}
#Provides
EventBus provideBus() {
return new EventBus();
}
#Provides //#Singleton
DownloadPrefs_ provideDownloadPrefs() {
return new DownloadPrefs_(MinimalBible.getApplication());
}
}
Also, how the graph gets created:
MinimalBible.java
public class MinimalBible extends Application {
private ObjectGraph graph;
private static MinimalBible instance;
public MinimalBible() {
instance = this;
}
#Override
public void onCreate() {
graph = ObjectGraph.create(new MinimalBibleModules());
graph.inject(this);
}
There are two parts here. First, how you get access to the Context. You can do static things as you are, though that's not advisable. Generally, you should configure your graph with a stateful module that carries the context, like this:
#Module
class ApplicationModule {
private final Application application;
public ApplicationModule(Application app) {
this.application = app;
}
// you can mark this singleton, but it's minor overhead
// and the fact that you have a single instance stored
// means it's semantically equivalent. But for clarity
// it's sometimes good to make the point.
#Provides
#Singleton
Application application() {
return application;
}
// optionally: bind it as a Context with a qualifier.
// note: never bind Context without a qualifier annotation
// as Activity and Application are both Context subtypes.
#Provides
#Singleton
#PerApplication
Context appContext(Application app) {
// Doing this instead of returning this.application is
// semantically equivalent but links #PerApplication Context
// to Application, so in graph analysis and error reporting
// the link is clearer. That's a personal choice.
return app;
}
}
At any rate, you then when you create the graph:
Application appInstance = ...;
ObjectGraph appGraph = ObjectGraph.create(
MyAppModule.class,
new ApplicationModule(appInstance));
The Application is then seeded into the graph and can be depended-upon by other types that declare it as a dependency.

Categories

Resources