Provide method dependendies - android

In the documentation it says that #Provides methods may have dependencies on their own, like:
#Provides Pump providePump(Thermosiphon pump) {
return pump;
}
What would change if I would write it like that:
#Provides Pump providePump() {
return new Thermosiphon();
}
And in the first snipped: Where does the method get its pump from?

The documentation also shows the Thermosiphon class:
class Thermosiphon implements Pump {
private final Heater heater;
#Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}
...
}
The constructor of this class is annotated with #Inject. This lets Dagger know to use this Constructor whenever a Thermosiphon is necessary, and automatically supplies a Heater instance to it, so you don't have to.
It is perfectly fine for you to create a new Thermospihon instance yourself, but Dagger saves you the trouble by doing it like this. For example, you would need to get some Heater reference from somewhere if you do it manually. That is what Dagger is all about, so you don't have to do the tedious repetitive work.

These are effectively the same IF a new instance of Thermosiphon.class is created every time you request an instance. If it's a singleton (or scoped in any way), then we have a difference.
If you have the following, then the first example is an alias to the singleton. The second example, however, will still create new instances every time.
#Provides
#Singleton
Thermosiphon provideThermosiphon() {
return new Thermosiphon();
}
Personally, I like the first approach better. Using the first approach, you could add or alter the provider later and adjust the scope or the state of the instance before it'a passed to the alias. It seems a little more flexible.

It looks for other beans declared in your module
For example:
#Module
public class MainModule {
#Provides
public EmailServiceApiGateway provideEmailServiceApiGateway() {
return new EmailServiceApiGateway();
}
#Provides
public EmailSendingActivityPresenter provideEmailSendingActivityPresenter(EmailServiceApiGateway emailServiceApiGateway) {
return new EmailSendingActivityPresenterImpl(emailServiceApiGateway);
}
}
So in the case above, EmailServiceApiGateway gets automatically injected into EmailSendingActivityPresenter.

Related

Dagger2 dependency injection: How does it work in an android app?

I am trying to understand an example for an app with offline support using retrofit and room:
You can find the code for it here:
This project is using dependency injections with Dagger2. I've never worked with it so I am trying to understand how things work together. I understand the purpose of dependency injection but I don't understand the implementation of the project above.
I found a very good introduction into Dagger2 here:
A Friendly Introduction to Dagger 2
Dagger 2 example Code:
I worked through it and got most of it. Back to the actual project I am trying to understand (link 2). It still doesn't make sense to me and here is why:
The interface AppComponent has one method which is used:
public void inject(MainActivity2ViewModel viewModelModule); The return type is void. In the Dagger2 sample project (link 3 and 4) they use WeatherReporter getWeatherReporter(); which makes sense because later they call this method to get a WeatherReporter-Instance and Dagger2 manages all of the instantation process in the background. But I get nothing if the return type is void. Why is the return type not an object?
There is one #Inject in MainActivity2ViewModel:
#Inject
public void setRepository(GitHubRepository2 repository) {
this.repository = repository;
}
repository is the only field of MainActivity2ViewModel so it is a dependency. The GitHubRepository2 constructor has 3 parameters:
#Inject
public GitHubRepository2(GitHubApi api, GitHubDao dao, Executor executor)
For each of them there is a module explaining how to create those objects. But why is there an AppModule and a NetModule? Maybe the AppModule is there because DaoModule needs an Application reference but why is there a NetModule and where is it used?
There's a lot of comprehensive tutorials about Dagger2 in Android. But I'll show you a glimpse of what it's used for. And minimal usage.
Ultimately, dagger will use the annotation #Inject which will provide(reference to the object or value) to the variable.
Injection is usually used on reusable or boilerplate objects like Dao, Repository, ViewModel, NetworkAdapter
class SomethingThatRequiresNetwork { // Activity, Fragment
#Inject
MyReusableNetworkAdapter myReusableNetworkAdapter;
String baseUrl; // for example purpose only
SomeDependency someDependency;
void init() {
// #NOTE: DaggerMyExampleComponent is a generated class. It will be red before compilation.
MyExampleComponent MyExampleComponent = DaggerMyExampleComponent.builder().build();
MyExampleComponent.inject(this); // the actual injection happens here
}
// yes, you can just use #Inject on the variables directly but this is another use.
#Inject
void methodInjection(String baseUrl, SomeDependency someDependency) {
this.baseUrl = baseUrl;
this.someDependency = someDependency;
}
}
// ANSWER to the two questions
// this is a pseudocode of the generated code. You do not write this
// MyExampleComponent class
void inject(SomethingThatRequiresNetwork obj) {
// #NOTE: modules are actually instantiated by MyExampleComponent. Not called statically. I just shortened it
obj.myReusableNetworkAdapter = NetModule.provideNetworkAdapter();
obj.methodInjection(NetModule.provideBaseUrl(), SomeModule.provideSomeDependency());
}
// these here are modules that provide by return TYPE
// you write these
#Module
class NetModule {
#Provides
#Singleton
String provideBaseUrl() {
return "www.some-url.com";
}
#Provides
#Singleton // will store the object and reuse it.
// #NOTE: provision can work internally within modules or inter-module. the input here is provided by provideBaseUrl
MyReusableNetworkAdapter provideNetworkAdapter(String baseUrl) {
return new MyReusableNetworkAdapter(baseUrl);
}
}
#Modules
class SomeModule {
#Provides
#Singleton
SomeDependency provideSomeDependency() {
return new SomeDependency();
}
}
// Component. uses modules
#Singleton // .build() will reuse
#Component(modules = {NetModule.class, SomeModule.class})
interface MyExampleComponent {
// the method name doesn't matter
// the class type does matter though.
void inject(SomethingThatRequiresNetwork somethingThatRequiresNetwork);
// some other class that needs injection. #NOTE: I did not give example for this
void inject(SomethingThatRequiresDependency some);
}
NOTE. This code is usually written from bottom to top lol. You start writing the Component then Module then Injections.
Just follow the calls from the top of this answer and you'll figure out how Dagger2 works.

Per scope dependency / overrideing dependencies per scope in Dagger2

I think the easiest way to explain is with a code example that includes RxJava
class SomeClass {
CompositeSubscriptions subscriptions;
public SomeClass(CompositeSubscription subscriptions) {
this.subscriptions = subscriptions;
subscriptions.add(...);
subscriptions.add(...);
subscriptions.add(...);
subscriptions.add(...);
subscriptions.add(...);
}
public void destory() {
subscriptions.unsubscribe();
}
}
So what I want to be able to do is to have classes just be able to ask for a CompositeSubscription and they get the one for there scope. That way they can freely unsubscribe the whole CompositeSubscription. This would be needed so that my Singletons don't interfere with my Activities which don't interfere with my Fragments.
You cannot have the same class provided in multiple scopes. You get an error {Class} is bound multiple times.
So the following setup is not valid
#Module
public class ActivityRxJavaModule {
#Provides
#PerActivity
CompositeSubscription providesCompositeSubscription() {
return new CompositeSubscription();
}
}
#Module
public class FragmentRxJavaModule {
#Provides
#PerFragment
CompositeSubscription providesCompositeSubscription() {
return new CompositeSubscription();
}
}
So there are two solutions that I know of.
Subclass per scope
a. Singleton{Class}, PerWhatever{Class}
Using the name annotation
a. #Named("singleton"), #Named("perwhatever")
I seem to prefer the Subclass per scope because I feel like it is a bit safer when refactoring, but both should work.

Dagger2 what is the purpose of adding a scope tag to components?

I've created a component and it only last for the lifetime of the activity. I did not use any scope annotations and only quick example of the life time of the component looks like this:
public class MainActivity extends AppCompatActivity {
private final String TAG = getClass().getSimpleName();
#Inject
AlmondButter someAlmondButter;
#Inject
CashewSandwich sandwich;
SandwichComponent sandwichComponent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*create thte dependent butter for the sandwich here*/
ButterComponent butterComponent=DaggerButterComponent.builder().
butterModule(new ButterModule()).build();
/*create a scope sandwichcomponent here */
sandwichComponent=DaggerSandwichComponent.builder().sandwichModule(new SandwichModule()).
butterComponent(butterComponent)
.build();
//finally we have a sandwichComponent, lets inject our dependencies
sandwichComponent.inject(this);
Log.v(TAG,sandwich.toString());
Log.v(TAG,someAlmondButter.toString());
}
#Override
protected void onDestroy() {
super.onDestroy();
//not necessary but it clearly shows the scope being tied to lifecycle of activity
sandwichComponent=null;
}
}
none of my components are scoped with anotations and it works fine. So im confused why some recommend to create scope tags, what is there purpose ? i'll show you my components below for reference:
#Component(dependencies = ButterComponent.class, modules = SandwichModule.class)
public interface SandwichComponent {
CashewSandwich ProvideCashewSandwitch();
void inject (MainActivity mainactivity);
}
and the next component:
#Component(modules={ButterModule.class})
public interface ButterComponent {
//these are for our whatever class depends on butter
AlmondButter ProvideAlmondButter();
CashewButter ProvideCashewButter();
}
UPDATE: FOR ANYONE WHO NEEDS HELP WITH UNDERSTANDING THESE CONCEPTS I MADE A BLOG HERE.
By using scopes on component and scopes on module provider method, you can ask Dagger2 to create scoped providers for you.
In order to get a scoped provider in your module's provider method, you must put the scope on the component as well.
You can specify only one scope on a given component, and in a scoped component, you can only have modules with that scope on its provider methods, or the provider methods can also be unscoped.
Unscoped providers give you a new instance on every inject call.
Scoped providers store a single instance for every inject call to that specific component instance.
#Component(modules={HelloModule.class})
#Singleton
public interface HelloComponent {
Hello hello();
World world();
void inject(MainActivity mainActivity);
}
#Module
public class HelloModule {
#Provides
public Hello hello() { return new Hello(); } //new instance each call to inject
#Provides
#Singleton
public World world() { return new World(); } //one instance per component
}
It is also worth noting that if you subscope another component to inherit its dependencies (using subcomponent or component dependency), you can only depend on one other scoped component. Think of it like how "multiple inheritance" is not allowed in Java, you also cannot depend on multiple scoped components and inherit their dependencies, only one.
Typically you have a singleton scope, and you subscope your components according to the top-level separation of modules in your application.
#Component(modules={ApplicationModule.class})
#Singleton
public interface ApplicationComponent {
Something something();
}
#Component(dependencies={ApplicationComponent.class}, modules={MainActivityModule.class})
#ActivityScope
//this is a subscoped component that inherits from ApplicationComponent
public interface MainActivityComponent extends ApplicationComponent {
OtherThing otherThing();
void inject(MainActivity mainActivity);
}
According to Martin Fowler, the right way to slice your application into pieces on the top-level is by features, such as GalleryComponent, SettingsComponent, etc. and not by layers (data, domain, presentation).
Scopes manage the instance creation across multiple requests for the same type. Imagine if you had this:
#Inject
AlmondButter someAlmondButter;
#Inject
AlmondButter otherAlmondButter;
This would create two separate AlmondButter instances. A trivial case, but hopefully it illustrates the point that each time you request the dependency, a new one is created.
Imagine now you have two different classes, each with a field #Inject AlmondButter sharedAlmondButter. If you want them to have the same exact instance, a scope will handle that for you.
Similarly, with any dependency you have, you can inject a Provider<T>, i.e. #Inject Provider<AlmondButter> almondButterProvider. This can allow you to call almondButterProvider.get() to retrieve a new instance. If you then wanted all values returned by .get() to be the same instance, a scope would accomplish the same thing.

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

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