How to declare dependencies - android

I'm studying Dagger 2 so I would like to understand some basic things. I have the following code:
#Module
public class MainModule {
#Provides
public Presenter provideMainActivityPresenter(Model model){
return new MainPresenter(model);
}
#Provides
public Model provideMainModel(){
return new MainModel();
}
}
and my MainPresenter class looks like this:
public class MainPresenter implements Presenter {
#Nullable
private ViewImpl view;
private Model model;
public MainPresenter(Model model) {
this.model = model;
}
#Override
public void setView(ViewImpl view) {
this.view = view;
}
}
Instead of the above code, could I do the following?
public class MainPresenter implements Presenter {
#Nullable
private ViewImpl view;
#Inject
Model model;
#Override
public void setView(ViewImpl view) {
this.view = view;
}
}
Because the MainPresenter depends on the Model and it is not #Nullable.
Or this is wrong?
I don't understand when I should put a dependency as a constructor argument, or when I should use #Inject

You have basically 3 ways to use Dagger
Constructor injection
Field injection
Providing it from a module yourself
(There is also method injection which calls a method after creating your object)
The following is using a module that provides your class. While not wrong, this is the most overhead to write and maintain. You create the object by passing in the requested dependencies and return it:
// in a module
#Provides
public Presenter provideMainActivityPresenter(Model model){
// you request model and pass it to the constructor yourself
return new MainPresenter(model);
}
This should be used with things that require additional setup, like Gson, OkHttp, or Retrofit so that you can create the object in one place with the required dependencies.
The following would be used to inject objects where you don't have access or don't want to use the constructo. You annotate the field and register a method at the component to inject your object:
#Component class SomeComponent {
void injectPresenter(MainPresenter presenter);
}
public class MainPresenter implements Presenter {
// it's not annotated by #Inject, so it will be ignored
#Nullable
private ViewImpl view;
// will be field injected by calling Component.injectPresenter(presenter)
#Inject
Model model;
// other methods, etc
}
This will also provide you with overhead to register all your classes at a presenter and should be used when you can't use the constructor, like Activities, Fragments, or with Services. That's why all those Dagger samples have those onCreate() { DaggerComponent.inject(this); } methods to inject parts of the Android framework.
Most importantly you can use Constructor Injection. You annotate the constructor with #Inject and let Dagger find out how to create it.
public class MainPresenter implements Presenter {
// not assigned by constructor
#Nullable
private ViewImpl view;
// assigned in the constructor which gets called by dagger and the dependency is passed in
private Model model;
// dagger will call the constructor and pass in the Model
#Inject
public MainPresenter(Model model) {
this.model = model;
}
}
This only requires you to annotated your class constructor and Dagger will know how to handle it, given that all the dependencies (constructor arguments, Model in this example) can be provided.
All of the methods mentioned above will create an object and can / should be used in different circumstances.
All of those methods either pass the dependencies to the constructor, or inject #Inject annotated fields directly. Dependencies should thuse be in the constructor or annotated by #Inject so that Dagger knows about them.
I also wrote a blog post about the basic usage of Dagger 2 with some further details.

Related

Why is my field `null` after injection? How do I inject my object?

This is a Canonical Question because there are a lot of misconceptions about object initialization with Dagger 2.
If your question was flagged as a duplicate please read this post carefully and make sure to understand the difference between constructor injection and field injection.
I try to inject a Context into my presenter, but I get a NullPointerException when trying to use it.
class MyPresenter {
#Inject Context context;
private MyView view;
#Inject
MyPresenter(MyView view) {
this.view = view;
}
}
My module looks like this
#Module
class MyModule {
#Provides
MyPresenter provideMyPresenter(MyView view) {
return new MyPresenter(view);
}
}
I inject the presenter in my Activity here:
class MyActivity extends Activity {
#Inject MyPresenter presenter;
#Override
public void onCreate(Bundle savedInstanceState) {
createMyActivityComponent().inject(this);
}
}
The above includes both constructor and field injection, but neither done right. The example would behave the same if we removed all the #Inject annotations from MyPresenter since we're not using any of them.
#Provides
MyPresenter provideMyPresenter(MyView view) {
// no constructor injection, we create the object ourselves!
return new MyPresenter(view);
}
// also no mention anywhere of component.inject(presenter)
// so the fields won't be injected either
Make sure to use either constructor injection or field injection. Mixing both will usually indicate an error in your setup or understanding.
#Inject on a field is a marker for field injection
#Inject on a constructor is a marker for constructor injection
This means your class should have either of
a single #Inject on the constructor, or
a #Inject on all the fields to initialize, but none on the constructor!
Don't sprinkle #Inject everywhere and expect things to work! Make sure to place the annotation where needed. Don't mix field and constructor injection!
Constructor injection should be favored over field injection as it creates an initialized and usable object. Field injection is to be used with Framework components where the Framework creates the objects. You have to manually call component.inject(object) for field injection to be performed, or any annotated fields will be null when you try to use them.
Constructor Injection
As the name suggests you put your dependencies as parameters in the constructor. The annotation on the constructor tells Dagger about the object and it can then create the object for you by calling it with all the required dependencies. Dagger will also inject any annotated fields or methods after creating the object, but plain constructor injection should usually be favored as it doesn't hide any dependencies.
Dagger creating the object also means there is no need for a #Provides method in your module that creates the object. All you need to do is add #Inject to the constructor and declare the dependencies.
class MyPresenter {
private Context context;
private MyView view;
#Inject
MyPresenter(MyView view, Context context) {
this.view = view;
this.context = context
}
}
If you want to bind your implementation to an interface, there is still no need to create the object yourself.
#Module class MyModule {
#Provides
MyPresenter providePresenter(MyPresenterImpl presenter) {
// Dagger creates the object, we return it as a binding for the interface!
return presenter;
}
}
And there is even a shorter (and more performant) version of the above use-case:
#Module interface MyModule {
#Binds
MyPresenter providePresenter(MyPresenterImpl presenter)
}
Constructor injection should be your default way of using Dagger. Make sure that you don't call new yourself or you misunderstood the concept.
Field Injection
There are times when you can't use constructor injection, e.g. an Activity in Android gets created by the Framework and you shouldn't override the constructor. In this case we can use field injection.
To use field injection you annotate all the fields that you want initialized with #Inject and add a void inject(MyActivity activity) method to the component that should handle the injection.
#Component
interface MyComponent {
void inject(MyActivity activity);
}
And somewhere in your code you have to call component.inject(myActivity) or the fields will not be initialized. e.g. in onCreate(..)
void onCreate(..) {
// fields still null / uninitialized
myComponent.inject(this);
// fields are now injected!
// ...
}
Field injection is not transitive. Just because you inject an Activity this does not mean that Dagger will also inject the fields of the presenter it injected. You have to inject every object manually, which is one reason why you should favor constructor injection.
There are tools that help mitigate the boilerplate of creating components and injecting your objects like AndroidInjection.inject() which will do this for you, but it still has to be done. Another example is AppInjector which adds various lifecycle listeners to inject your Activities and Fragments, but it will still call AndroidInjection which then creates your component and injects the object.
Make sure that you inject the object before using it and that there is no constructor annotated with #Inject to avoid confusion.
What else?
There is also the lesser used method injection and of course Dagger can't inject third party libraries, which you have to construct and provide in your modules.
Remove #Inject from the Context and create a separate module for providing Context dependency
#Module
public class ContextModule {
private final Context context;
public ContextModule(Context context) {
this.context = context;
}
#Provides
#MyAppScope
public Context getContext() {
return context;
}
}
then create your DaggerComponent. (I have created it in Application class and this refers to ApplicationContext
component = DaggerDaggerAppComponent.builder()
.contextModule(new ContextModule(this))
.MyModule()
.build();
You can skip .MyModule() if you want because unlike Context module it has no external dependency.

dagger2 constructor injection how to provide dependency without module

I've read that constructor injections don't require a module.
So I have this questions.
If I have this constructor injection:
private Model realmModel;
#Inject
public MainActivityPresenter(Model realmModel) {
this.realmModel = realmModel;
}
and this component:
#Singleton
#Component(modules = {AppModule.class})
public interface AppComponent {
Model realmModel();
void inject(MainActivity activity);
}
if in my MainActivity I do it:
((MyApp)getApplication()).createAppComponent().inject(this);
how could I pass the realmModel parameter to the presenter constructor injection?
EDIT: this is the model:
Presenter presenter;
#Inject
public RealmModel(Presenter presenter) {
this.presenter = presenter;
}
Thanks
Three ways to solve this problem
1) Give a module which does the provide of the Relam Model
#Provides
#Singleton
public Model providesRealmModel() {
return new Model();
}
2) Make your RelamModel class also constructor injected
class Model {
#Inject
public Model() {}
}
The Trick in construction injection is all its dependencies should also be constuctor injeceted then it would work fine.
(From experience your model would need application context. look at the 3 option for ways to implement external Dependencies
3) Provide Model as external dependency.
#Module
public class ModelModule {
private Model relamModel;
public ModelModule(Model relamModel) {
this.relamModel = relamModel
}
}
#Component(module={ModelModule.class})
public interface ApplicationComponent {
}
Take a look at the series of videos from twisted eqautions these were my first video tutorial on dagger2. I found it really helpful. Hope it helps you too
https://www.youtube.com/watch?v=Qwk7ESmaCq0
You have two choices:
use a module with a provide method
annotate the constructor of Model with #Inject, doing that when you pass realmModel in the presenter contructor, the model
constructor will be called.
I prefer to use modules, but that's just my opinion.

Dagger - Getting Same Instance On Different Component

I'm having a similar problem like the one in this question.
While the accepted answer does help, but I'm missing final piece to solve the problem.
I have 2 android library modules: common and exp which depends on common.
Everything under common:
#Module
public class CommonModule {
#Singleton
#Provides
public Repository providesRepository() {
return new Repository();
}
}
#Singleton
#Component(modules={CommonModule.class})
public interface CommonComponent {
void inject(CommonClass commonClass);
/**
CommonClass needs instance of Repository
**/
}
public class CommonDIHolder {
public static CommonComponent sComponent;
public static void init() {
sComponent = DaggerCommonComponent.builder().build();
}
}
Everything under exp:
#Module(includes={CommonModule.class})
public class ExpModule {
#Singleton
#Provides
public ExpResource provideExpResource() {
return new ExpResource();
}
}
#Singleton
#Component(modules={ExpModule.class}, dependencies={CommonComponent.class})
public interface ExpComponent {
void inject(ExpClass expClass);
/**
ExpClass needs instance of Repository and ExpResource
**/
}
public class ExpDIHolder {
public static ExpComponent sComponent;
public static void init() {
sComponent = DaggerExpComponent.builder()
.commonComponent(CommonDIHolder.sComponent)
.build();
}
}
I need both CommonClass and ExpClass receive the same instance of Repository.
The problem with this approach is that #Singleton can't depends on #Singleton. So I have to change the scope of ExpComponent into self-defined scope called #ExpScope. Then I changed the provideExpResource into #ExpScope as well.
Then I encountered an error saying that ExpComponent may not reference bindings with different scopes. It refers to the provideRepository which has different scope (#Singleton) on it. If I changed the scope into ExpScope then the CommonComponent will have different scope with provideRepository.
If I changed all #Singleton into #ExpScope then I receive this error message: depends on scoped components in a non-hierarchical scope ordering
What should I do? Or I'm doing the wrong approach here?
Use one and only one #Singleton scoped component
You should have one and only one #Singleton scoped component like this:
#Singleton
#Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {
}
Only specify Activities, Fragments, and Services as explicit injection targets for Components
In an Android app, you should only list Activities, Fragments and Services as injection sites. You should configure Dagger 2 to inject the rest of your dependencies without having to resort to calling component.inject(this) inside them.
For example, if your CommonClass looks like this:
public class CommonClass {
#Inject Repository repository;
public class CommonClass() {
CommonComponentHolder.get().inject(this);
}
}
Refactor it like this:
public class CommonClass {
private final Repository repository;
#Inject
public class CommonClass(Repository repository) {
this.repository = repository;
}
}
Now when you have an Activity or Fragment that needs CommonClass and you are injecting with CommonComponent or one of its sub-components or dependent components, they can obtain instances of CommonClass wired with the correct dependencies:
public class MyActivity extends AppCompatActivity {
#Inject CommonClass commonClass;
public void onCreate(Bundle savedInstanceState) {
CommonComponentHolder.getComponent().inject(this);
}
}
Use subcomponents or dependent components to specify the injection targets
Now you have a #Singleton scoped component, you'll probably want to create a component for a narrower scope for your Activity or Fragment. You'll have to connect it to your CommonComponent, so use dependent components or subcomponents (subcomponents are preferred as of Dagger 2.10). Since you say you have already tried defining a #ExpScope, I think the missing piece is to make subcomponent or dependent component with the #ExpScope that injects your Activity or Fragment.
Something like the following for the top-level singleton component:
#Singleton
#Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {
ExpComponent.Builder exComponent();
}
And then for the subcomponent:
#ExpScope
#Subcomponent(modules = {NarrowerScopedModule.class})
public interface ExpComponent {
#Subcomponent.Builder
public interface Builder {
Builder narrowerScopedModule(NarrowerScopedModule narrowerScopedModule);
ExpComponent build();
}
}
There are good working examples of Android projects in the Google Android Architecture Blueprints Github repo

How to inject a Presenter into a View (MVP pattern) using Dagger2

I want to build an Android app using the MVP pattern.
I have a fragment (the view) and a presenter class.
What I want is to basically inject the presenter into the fragment, and set the fragment as the presenter's view (via an interface that the view will implement)
How can I easily and correctly connect the 2 using dependency injection (with Dagger2)?
Edit:
In addition, I'd like the presenter to be a singleton, so it will be able to persist data & state across orientation changes
First you need to define a presenter module:
#Module
class SearchPresenterModule {
#NonNull
private final SearchContract.View mView;
SearchPresenterModule(#NonNull SearchContract.View view) {
this.mView = view;
}
#Provides
SearchContract.View provideSearchContractView() {
return mView;
}
}
Here's the example component:
#FragmentScoped
#Component(modules = SearchPresenterModule.class)
interface SearchComponent {
void inject(SearchActivity activity);
}
And inject your presenter:
#Inject
SearchPresenter mSearchPresenter;
DaggerSearchComponent.builder()
.searchPresenterModule(new SearchPresenterModule(searchFragment))
.build()
.inject(this);
Finally inject your presenter's constructor:
#Inject
SearchPresenter(#NonNull SearchContract.View view, #NonNull SearchRepository searchRepository) {
this.mView = view;
mView.setPresenter(this);
}
Extra: Here's fragmentscoped annotation:
#Documented
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface FragmentScoped {
}
You can check my example repo for MVP + DAGGER2
https://github.com/savepopulation/wikilight
so the presenter is like
#Singleton
public class Presenter{
private View mView; ...
the view should be
public class View extends ...{
#Inject
protected Presenter mPresenter ...
Well, you just need a method in your module like
inject(View view)
and Dagger should take care of the rest like the singleton instance and the injection

Dagger - nested injections, is it necessary to call inject()?

I'm new to Dagger and at the begininig I face some issues. I have simple structure so far in my project. My injection module:
#Module(
injects = {GameBoardFragment.class, GameManager.class},
complete = false,
library = true
)
public class GameObjectsProviderModule {
private final Application mApplication;
public GameObjectsProviderModule(Application application){
this.mApplication = application;
}
#Provides
#Singleton
public GameManager provideGameManager(){
return new GameManager();
}
#Provides
public Board getBoard(){
return new Board();
}
#Provides #Singleton #ForApplication Context provideAppContext() {
return mApplication;
}
My simplified custom app class looks like that:
public class MyApp extends Application {
private static ObjectGraph mApplicationGraph;
#Override public void onCreate() {
super.onCreate();
mApplicationGraph = ObjectGraph.create(new GameObjectsProviderModule(this));
}
public static ObjectGraph getObjectGraph(){
return mApplicationGraph;
}
}
And now, my fragment looks like that:
public class GameBoardFragment extends Fragment {
#Inject
GameManager mGameManager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
MyApp.getObjectGraph().inject(this);
View root = inflater.inflate(R.layout.fragment_game_board, container, false);
findViews(root);
confViews();
return root;
}
}
And finally my GameManager class
public class GameManager {
#Inject Board mBoard;
public GameManager(){
MyApp.getObjectGraph().inject(this);
}
}
Andy hey, it works! Great. But my question is why it doesn't work in case I comment out this line:
MyApp.getObjectGraph().inject(this);
Do we have always explicitly call inject() function to make all necessary injections take place event in nested objects?
It looks not, as shows coffe maker example:
https://github.com/square/dagger/tree/master/examples/simple/src/main/java/coffee
Why then I have to call inject() in GameManager class to get it working?
Edit:
The consturctor injection approach works just fine.
But for future use I tried to get field injection running, and so far I haven't succeed.
I commented out both #Provide methods from module and I made my GameManager look like this:
#Singleton
public class GameManager {
#Inject Board mBoard;
#Inject
public GameManager(){
}
}
and Board:
public class Board {
#Inject
public Board() {
}
}
However mBoard doesn't get instantiated. I will try more and I suppose I figure out the proper solution.
You should rather use constructor injection (like for example the Thermosiphon does), and avoid field injection unless necessary. For example, let your GameManager have the Board as a constructor argument:
#Singleton
public class GameManager {
private final Board mBoard;
#Inject
public GameManager(final Board board){
mBoard = board;
}
}
Dagger will use this constructor to create an instance of the GameManager (hence the #Inject annotation), and notice it needs a Board instance. Using the ObjectGraph, it will create a Board first, and use that instance to create the GameManager. You can remove the #Provides GameManager method if you do it this way.
In your case, you have a #Provides Board method in your module. If you add an #Inject annotation to your Board constructor, you can remove this provides-method from your module:
public class Board {
#Inject
public Board() {
}
}
If you don't want to use constructor injection, the problem is that you told Dagger that you want to create your GameManager instance yourself (because you have the #Provides GameManager method). If you remove this method, and let Dagger create it for you like above but without the Board parameter in the constructor, Dagger will also notice the #Inject Board field and inject that as well.
A final remark. Remove the library = true and complete = false statements! These are not necessary at all in this example. Only add them if you really know what you're doing. By not having them, Dagger will create compile-time errors to notify you that something is wrong. If you do include them, you're telling Dagger "Hey, I know what I'm doing, don't worry, it's all correct", when in fact it isn't.
Edit
A quote from the Dagger1 site:
If your class has #Inject-annotated fields but no #Inject-annotated
constructor, Dagger will use a no-argument constructor if it exists.
Classes that lack #Inject annotations cannot be constructed by Dagger.
I do not use this method very often, so I could be wrong. I think this means that you should remove the #Inject annotation from your constructor, like so:
#Singleton
public class GameManager {
#Inject Board mBoard;
public GameManager(){ // Or remove the constructor entirely since it's empty
}
}
Since there is an #Inject annotation on the Board field, Dagger will know to use the no-argument constructor.
I was struggling with the same issue as most of the dagger examples everywhere use a Module with Provides and I had a hard time finding a complete example that just does not use Provides.
I created this one. It uses field injection (not constructor injection) and works just fine through the hierarchy without requiring any call to inject. I am using Dagger 1.2.2.
Main.java
import javax.inject.*;
import dagger.*;
import dagger.ObjectGraph;
public class Main {
public static void main(String[] args) {
ObjectGraph objectGraph = ObjectGraph.create(new CarModule());
Car car = objectGraph.get(Car.class);
car.start();
}
}
CarModule.Java
import dagger.Module;
#Module(injects = Car.class)
public class CarModule {
}
Car.Java
import javax.inject.*;
public class Car {
#Inject public Engine engine;
#Inject Car() {
System.out.println("Car constructor");
}
public void start() {
engine.start();
}
}
Engine.Java
import javax.inject.*;
public class Engine {
#Inject WaterPump waterPump;
Engine() {
System.out.println("Engine Constructor");
}
void start() {
waterPump.run();
System.out.println("starting engine.");
}
}
WaterPump.Java
import javax.inject.*;
public class WaterPump {
#Inject WaterPump() {
System.out.println("WaterPump Constructor.");
}
public void run() {
System.out.println("WaterPump running.");
}
}
The output is:
Car constructor
Engine Constructor
WaterPump Constructor.
WaterPump running.
starting engine.
Without The CarModule that declares it injects Car.Class this does not work. You get:
Exception in thread "main" java.lang.IllegalArgumentException: No
inject registered for members/Car. You must explicitly add it to the
'injects' option in one of your modules.
But notice that CarModule does not #Provides anything. It is dagger that automatically creates all the dependencies using the object graph.
Also note that you don't have to place an #Inject annotation on the default constructor if you have a #Inject field in the class. For Car class I used it on both the constructor and the field and in Engine class I used it just for the field and not for the constructor and it works fine as documented.

Categories

Resources