Dagger

A Problem - Solution Approach

Dependency Injection Framework

1.

What is

"dependency injection" ?

It means giving an object its instance variables.

Really. That’s it.

public class Example {
  private Something something;

  public Example() {
    this.something = new Something();
  }

  public void DoStuff() {
    ...
    something.doSomething();
    ...
  }
}
public class Example {
  private Something something;

  public Example(Something someOtherThing) {
    this.something = someOtherThing;
  }

  public void setSomething(Something someOtherOtherThing) {
    this.something = someOtherOtherThing;
  }
}

2.

Why

"dependency injection" ?

It’s handy for isolating classes during testing.

public class ExampleTest {
  TestDoStuff() {
    MockSomething mockSomething = new MockSomething();

    // MockSomething is a subclass of Something, so we can
    // "inject" it here:
    Example example = new Example(mockSomething);

    example.DoStuff();
    mockSomething.AssertDoSomethingSuccessfully();
  }
}

That’s it.

Dependency injection is really just passing in an instance variable.

3.

What is Dagger ?

Dagger is a dependency injection framework

for Java and Android.

4.

Why Dagger ?

Let's examine this

4.

Why Dagger ?

Dependency Inject without Dagger

new Person(new Body(new Blood()));
// OBlood, ABlood, BBlood, ABBlood

5.

Goal of Dagger ?

Separates

the creation of a client’s dependencies

from

the client’s behavior

all calls of new operator, newInstance() and others shouldn’t be invoked in places

other than Dagger’s Modules.

new Person(new Body(new Blood()));
// OBlood, ABlood, BBlood, ABBlood

5.

Goal of Dagger ?

public static void main(String[] args) {
  OBloodPersonCreator OBloodPersonCreator 
  	= DaggerOBloodPersonCreator.create();
  Person OBloodPerson = OBloodPersonCreator.createPerson();
  System.out.println(OBloodPerson);

  ABloodPersonCreator ABloodPersonCreator 
  	= DaggerABloodPersonCreator.create();
  Person ABloodPerson = ABloodPersonCreator.createPerson();
  System.out.println(ABloodPerson);
}

all calls of new operator, newInstance() and others

shouldn’t be invoked in places

other than Dagger’s Modules.

Dagger Fundamentals

@Inject @Provides @Module @Component

@Named @MyOwnAnnotation @IntoMap @MapKey @Provided @AutoFactory

@Inject

injects the Body  class into another class when needed

public class Body {

    @Inject
    public Body(){}

}
public class Person{

  Body body;

  @Inject
  public Person(Body body){
    this.body = body;
  }
}
public class Body {

    @Inject
    Blood blood;

    @Inject
    public Body(){}

    public Blood getBlood() {
        return blood;
    }
    
    public void setBlood(Blood blood) {
        this.blood = blood;
    }
}

@Module

injects concrete classes for an interface

@Module
public class RandomBloodModule {

    private static Blood blood;

    public RandomBloodModule() {

    }
    
    @Provides
    static Blood provideBlood(){
        if(blood != null) {
            return blood;
        }
        
        Random rnd = new Random();
        int rndNumber = rnd.nextInt(3);
        switch (rndNumber){
            case 0: blood = new A_Blood(); break;
            case 1: blood = new B_Blood(); break;
            case 2: blood = new AB_Blood(); break;
            case 4: blood = new O_Blood(); break;
            default: blood = new A_Blood();
        }
        return blood;
    }
}

@Component

an interface that specifies which modules to use

@Component( modules = RandomBloodModule.class )
public interface PersonCreator {
    Person createPerson();
}

That's it !

You can run your first Dagger project

public static void main(String[] args) {
  PersonCreator PersonCreator = DaggerPersonCreator.create();
  Person person = PersonCreator.createPerson();
  System.out.println(Operson);
}

Some more COMMON

annotations...

@Singleton

always inject the same instance

@Module
public class ABloodPersonCreatingModule {

    @Singleton
    @Provides
    Blood provideBlood(OBlood oBlood) {
        return oBlood;
    }

}
@Singleton
public class OBlood implements Blood {
    @Override
    public String getKindOfBlood() {
        return "O";
    }
}

@Named

2 provide methods that have the same return type

 

@Named annotation  differentiates two instances.

@Module
public class BloodModule {

    @Provides
    @Named("oblood")
    Blood provideOBlood() {
        return new OBlood();
    }

    @Provides
    @Named("ablood")
    Blood provideABlood() {
        return new ABlood();
    }

}
public class Body {

    @Inject
    @Named("oblood")
    Blood oBlood;

    @Inject
    @Named("ablood")
    Blood aBlood;
    
 }

@MyOwn

Annotation

Same use as @Named

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface OBloodQualifier {
}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ABloodQualifier {
}

public class Body {

    @Inject
    @OBloodQualifier
    Blood oBlood;

    @Inject
    @ABloodQualifier
    Blood aBlood;
    
 }

@IntoSet

package dependencies from different modules into a SET

@Module
public class BloodModule {

    @Provides
    @IntoSet
    Blood provideOBlood() {
        return new OBlood();
    }

    @Provides
    @IntoSet
    Blood provideABlood() {
        return new ABlood();
    }

}
@Component(modules = {
        BloodModule.class
})
public interface BloodPersonCreator {

    Set<Blood> getBloods();

}

It could then be injected all together to the target object.

@IntoMap

@Module
public class BloodModule {

    @Provides
    @IntoMap
    @StringKey("oblood")
    Blood provideOBlood() {
        return new OBlood();
    }

    @Provides
    @IntoMap
    @StringKey("ablood")
    Blood provideABlood() {
        return new ABlood();
    }
}
@Singleton
@Component(modules = {
        BloodModule.class
})
public interface BloodPersonCreator {

    Map<String, Blood> getBloods();

}

package dependencies from different modules into a MAP

It could then be injected all together to the target object.

@MapKey

@MapKey
  @interface BloodEnumKey {
   BloodEnum value();
 }

  @Module
 class BloodModule {
   @Provides
   @IntoMap
   @BloodEnumKey(Blood.O)
   Blood provideOBlood() {
     return new OBlood();
   }
 }

 class Body {
   @Inject
   Body (Map<SomeEnum, Integer> map) {
     assert map.get(BloodEnum.O)
     			.equals(new OBlood());
   }
 }

Same use as @IntoMap, but we define our own Key

Instead of using custom MapKey, you can use default keys provided by dagger — @StringKey, @IntKey, @LongKey, @ClassKey

@AutoFactory

@Provided

Generate the static create() method for

multi-parameters constructor

@AutoFactory
public class Soul {

    String type;

    public Soul(@Provided Body body, 
    				String type) {
        this.type = type;
    }
}
public class Person {

    Body body;
    Soul soul;

    @Inject
    public Person(Body body, SoulFactory soulFactory) {
        this.body = body;
        soul = soulFactory.create("male");
    }
}

Thanks for listening

Any Questions ?

Dagger

By dannguyencoder

Dagger

Dagger - Dependency Injection Framework - A Problem Solution Approach

  • 305