Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplest way to create a Singleton w/ Dagger 2?

Tags:

Do I need to setup Modules, Providers and Interfaces (Components)? Seems like quite a bit of overhead just to be able to inject a singleton.

Can someone provide a simple singleton example using Dagger 2? (also show how one can set properties of the singleton like the context so you don't need to pass it in every time you use the singleton)

like image 452
My House Avatar asked Aug 23 '16 01:08

My House


People also ask

What is singleton in dagger?

Dagger generates absolutely the same code, as when we defined a @Singleton . This means singletons will be created in the component regardless of what scope annotation is used.

What is@ Inject in Dagger?

Dagger 2 is a compile-time android dependency injection framework that uses Java Specification Request 330 and Annotations. Some of the basic annotations that are used in dagger 2 are: @Module This annotation is used over the class which is used to construct objects and provide the dependencies.

What is field injection in Dagger 2?

Dagger is a fully static, compile-time dependency injection framework for both Java and Android. It is an adaptation of an earlier version created by Square and now maintained by Google.


2 Answers

You only need modules for things that you can't annotate with @Inject constructor (because for example, the framework creates it for you - like context). If you can't add an @Inject constructor, you also need to specify a void inject(...) method in the component as well.

However, if you can create it with a @Inject constructor, then @Inject works as a field annotation as well

@Component(modules={ContextModule.class}) @Singleton public interface SingletonComponent {     void inject(MainActivity mainActivity); }  @Module public class ContextModule {     Context context;      public ContextModule(Context context) {         this.context = context;     }      @Provides     Context context() {         return context;     } }  @Singleton public class MyOtherSingleton {     @Inject     public MyOtherSingleton() {     } }   @Singleton public class MySingleton {     @Inject Context context;     @Inject MyOtherSingleton myOtherSingleton;      @Inject     public MySingleton() {     } } 

You can also do constructor parameters

private final Context context; private final MyOtherSingleton myOtherSingleton;  @Inject public MySingleton(Context context, MyOtherSingleton myOtherSingleton) {     this.context = context;     this.myOtherSingleton = myOtherSingleton; } 

SingletonComponent singletonComponent = DaggerSingletonComponent.builder()            .contextModule(CustomApplication.this)            .build();  // and elsewhere  @Inject MySingleton mySingleton;  // ...     singletonComponent.inject(this); 

Verified to work:

08-23 04:39:28.418 com.zhuinden.rxrealm D/DogView: My singleton has [com.zhuinden.rxrealm.application.CustomApplication@53348a58] and [com.zhuinden.rxrealm.application.injection.test.MyOtherSingleton@5336bb74] 08-23 04:39:36.422 com.zhuinden.rxrealm D/CatView: My singleton has [com.zhuinden.rxrealm.application.CustomApplication@53348a58] and [com.zhuinden.rxrealm.application.injection.test.MyOtherSingleton@5336bb74] 
like image 55
EpicPandaForce Avatar answered Nov 23 '22 05:11

EpicPandaForce


This is a simplified (not completely precise -- check links below) text gradually explaining Dagger2 and the idea behind it. My hopes are that you'll be able to read and understand other details on Dagger2 after this text.

Don't focus on the term singleton. Dagger2 (forget dagger and use dagger2) exists to enforce object scope. Not the scope we usually talk about (classes, methods, loops) but the scope on an architectural level (you define those layers).

Some typical layers in Android are Application, Activity and Fragment. As you know, your android app gets only one instance of Application class. Many instances of Activity class and many instances of Fragment class.

You want to keep your app nice and clean and you want to keep your objects right where they belong (enforce semantics). These objects need to be created somewhere (usually you have to type factory classes/methods/projects --last one was a joke), that creation utility needs to be called somewhere and you need to pass those objects from somewhere to where they belong!

That's a lot of somewheres to type (usually classes with strange names) and passing down those objects from where they were created to where they belong can be quite a challenge. Especially when many different classes use that special object of yours.

Dagger2 to the rescue! Basically there are two terms you need to understand. Components and Modules.

Components are here to inject. They inject your classes with objects they require to be constructed. Components only inject, they don't create the objects. So who creates objects?

Modules create objects that Components inject into classes that need to be constructed. Modules are full of provideInsertName methods. These methods create objects that you need to pass to classes that need them. A provide method will always create a new object or it will reuse (singleton) already created object if that provide method is annotated with @Scope (you'll need to type a new scope annotation but that's detail). Names of provide methods don't really matter. What matters is the return type of these methods (just remember that information it will be useful later).

When you type your Component you need to say which Modules are associated with that Component and during Component instantiation you will have to pass associated Module instances to that Component constructor. Together, Components and Modules form a mean injecting machine.

Instantiate your Component (Dagger2 generates builder classes for your Components) in the layer you feel that Component should inject. For instance, you create an ApplicationComponent instance inside Application class. Objects injected by ApplicationComponent are created only once and they exist while ApplicationComponent instance exists (during injection they will be fetched, not recreated). ApplicationComponent instance exists while Application instance exists (so in Android enviroment that's basically always/during app lifetime).

You can repeat the same story with Activity classes. Instantiate ActivityComponent inside your Activity class, that Component exists while that Activity exists. Notice how objects injected by ActivityComponent exist only while ActivityComponent (Activity class instance) exists. That's the beauty of Dagger2. Objects that belong to Activity layers are literally scoped to the Activity layer.

Note: Components can depend on each other. Your ActivityComponent can depend on your ApplicationComponent so Activity layer can use objects from Application layer (but not other way around, that's bad design). This way, Components form a dependency tree which makes object fetching and injection very efficient.

After reading this (my congratulations good sir) I recommend checking out this link and checking out Jake Wharton's talk on Dagger2.

like image 31
Spidey Avatar answered Nov 23 '22 05:11

Spidey