2. About
Joan
Puig
Sanz
• Electrical
Engineer
• So<ware/hardware
fan
:)
• Open
Source
Projects:
– ServDroid:
Simple
web
Server
– BeyondAR
Framework:
Augmented
Reality
framework
beyondar.com
1
3. //TODO:
1. What
is
Dependency
Injec+on?
2. Simple
Example:
Factory
PaPern
3. Android
and
Dependency
Injec+on
– KitKatMachine
example
with
RoboGuice
and
Dagger
– Compare
RoboGuice
and
Dagger
4. Conclusions
2
4. What
is
Dependency
Injec+on?
“Dependency
injec+on
is
a
so<ware
design
paPern
that
allows
the
removal
of
hard-‐coded
dependencies
and
makes
it
possible
to
change
them,
whether
at
run-‐+me
or
compile-‐+me”
Dependency
Injec+on
is
like
ordering
a
hawaiian
pizza
but
specifying
the
ingredients,
for
instance,
instead
of
ham
we
want
pepperoni.
3
5. What
does
Dependency
Injec+on
do?
• It
improves
the
code:
reusable,
modulable
and
testability
• It
allows
the
developer
to
focus
on
the
code
that
adds
a
plus
value
to
the
app:
– No
need
to
worry
about
Singletons,
Factories
and
others.
4
7. The
Factory
PaPern
public interface Heater {
public void on();
public void off();
public boolean isHot();
}
public class ElectricHeater implements Heater {
private boolean heating;
public void on() {
heating = true;
}
public void off() {
heating = false;
}
public boolean isHot() {
return heating;
}
}!
Heater
void
on()
void
off()
boolean
isHot()
ElectricHeater
6
8. The
Factory
PaPern
–
wri+ng
it
public class HeaterFactory {
private HeaterFactory () {}
private static Heater instance = new ElectricHeater();
public static Heater getInstance() {
return instance;
}
public static void setInstance(Heater heater) {
instance = heater;
}
}
public class HotMachine{
public void start(){
heater = HeaterFactory.getInstance();
heater.on();
// Other stuff
}
}!
7
9. The
Factory
PaPern
–
Unit
Test
public void testHeater(){
Heater previous =
HeaterFactory.getInstance();
try{
Heater mock = new mockHeater();
HeaterFactory.setInstance(mock);
HotMachine machine = new HotMachine();
machine.start();
assertTrue(mock.isHot());
}finally{
HeaterFactory.setInstance(previous);
}
}
8
10. Implementa+on
drawbacks
• For
every
dependency
we
make
we
need
to
write
the
same
code.
• Our
test
had
to
pass
the
mock
to
the
factory
and
then
clean
up
a<erwards.
• You
cannot
determine
if
HotMachine
depends
on
Heater
at
first
sight
• It
could
be
difficult
to
reuse
HotMachine
in
a
different
context
9
11. Implementa+on
drawbacks
• For
every
dependency
we
make
we
need
to
write
the
same
code.
• Our
test
had
to
pass
the
mock
to
the
factory
and
then
clean
up
a<erwards.
• You
cannot
determine
if
Machine
depends
on
Heater
at
first
sight
• It
could
be
difficult
to
reuse
Machine
in
a
different
context
10
12. Factory
PaPern
with
DI
•
We
need
to
define
a
module
specifying
what
are
we
going
to
inject.
– Heater
as
ElectricHeater
– We
also
can
define
how.
public class HotMachine{
private final Heater heater;
@Inject
public HotMachine(Heater heater){
this.heater = heater;
}
public void start(){
heater.on();
//Other stuff
}
}!
11
13. Factory
PaPern
with
DI
–
Unit
Tes+ng
!
public void testHeater(){
Heater mock= new mockHeater();
HotMachine machine = new HotMachine(mock);
machine.start()
assertTrue(mock.isHot());
}!
12
15. Android
• We
can
create
one
ourselves…
but
it
is
not
needed
and
it
is
a
lot
of
work
• The
best
ones
are
RoboGuice
and
Dagger
– RoboGuice
does
injec+on
during
run+me
• hPps://github.com/roboguice/roboguice
– Dagger
Generates
code
• hPps://github.com/square/dagger/
14
16. Example
-‐
KitKat
Machine
• Chocolate
• Cookie
• Machine
Chocolate
Heater
Machine
– Heater
– Mold
Cookie
Mold
The
source
code
can
be
found
here:
hEp://beyondar.com/di.html
15
17. Example
-‐
KitKat
Machine:
Steps
1.
2.
3.
4.
Define
dependencies
Create
modules
Prepare
the
graph
Inject
dependencies
16
20. Example
–
KitKat
Machine:
Dependencies
!
public interface Cookie {
public void doWhatCookiesDo();
}
public class TastyCookie implements Cookie{
@Inject
public TastyCookie(){
print("New cookie");
}
public void doWhatCookiesDo(){
print("Yummie yummie”);
}
}!
Cookie
void doWhatCookiesDo()
TastyCookie
19
21. Example
–
KitKat
Machine:
Dependencies
public interface Machine {
public void makeKitKat(Chocolate chocolate, Cookie cookie);
}!
RoboGuice
@Singleton
public class KitKatMachine implements Machine{
private Mold mold;
private Heater heater;
@Inject
public KitKatMachine(Mold mold, Heater
heater) {
this.mold = mold; this.heater = heater;
}
public void makeKitKat(Chocolate chocolate,
Cookie cookie){
heater.on();
Chocolate meltedChocolate =
heater.melt(chocolate);
mold.putToghether(cookie, chocolate);
print (”Kitkat ready”);
}
Dagger
public class KitKatMachine implements Machine{
private Mold mold;
private Lazy<Heater> heater;
@Inject
public KitKatMachine(Mold mold, Lazy<Heater>
heater) {
this.mold = mold; this.heater = heater;
}
public void makeKitKat(Chocolate chocolate,
Cookie cookie){
heater.get.on();
Chocolate meltedChocolate =
heater.get().melt(chocolate);
mold.putToghether(cookie, chocolate);
print (”Kitkat ready”);
}
20
22. Example
-‐
KitKat
Machine:
Modules
RoboGuice
public class kitkatModule extends
AbstractModule {
protected void configure(){
bind(Cookie.class).
toProvider(CookieProvider.class);
bind(Chocolate.class).
toProvider(ChocolateProvider.class);
bind(Machine.class).
to(KitkatMachine.class)
}
}
public class ChocolateProvider implements
Provider<Chocolate>{
@Override
public Chocolate get() {
return new ChocolateWithMilk();
}
}
Dagger
@Module
public class KitkatModule {
@Provides public Chocolate
provideChocolate() {
return new ChocolateWithMilk();
}
@Provides public Cookie
provideCookie(){
return new TastyCookie();
}
@Provides @Singleton public Machine
}
providesMachine(KitKatMachine machine){
return machine;
}
21
23. Example
-‐
KitKat
Machine:
Preparing
the
Graph
RoboGuice
public class KitKatMachineApplication extends
Application {
public void onCreate() {
super.onCreate();
RoboGuice.setBaseApplicationInjector
(this, Stage.PRODUCTION,
getModules());
}
protected Module[] getModules() {
List<Module> modules =
new ArrayList<Module>();
modules.add(
RoboGuice.newDefaultRoboModule(this));
modules.add(new IngredientsModule());
modules.add(new MachineModule());
return (Module[]) modules.toArray(new
Module[modules.size()]);
}
}
Dagger
public class KitKatMachineApplication extends
Application{
private ObjectGraph graph;
public void onCreate() {
super.onCreate();a
graph = ObjectGraph.create(
getModules().toArray());
}
protected List<Object> getModules() {
ArrayList<Object> modules =
new ArrayList<Object>();
modules.add(new AndroidModule(this));
modules.add(new IngredientsModule());
modules.add(new MachineModule());
return modules;
}
public void inject(Object object) {
graph.inject(object);
}
public ObjectGraph getApplicationGraph() {
return graph;
}
22
24. Example
-‐
KitKat
Machine:
Injec+ng
dependencies
public class HomeFragment extends #########{
@Inject Provider<Chocolate> chocolate;
@Inject Provider<Cookie> cookie;
@Inject Machine machine;
// With Dagger we can use Lazy<Machine> to create a lazy singleton
onResume(){
super.onResume()
machine.makeKitKat(chocolate.get(), cookie.get());
}
}
#########
• RoboGuice:
RoboFragment
• Dagger:
BaseFragment
(your
custom
BaseFragment)
23
25. Example
-‐
KitKat
Machine:
Injec+ng
dependencies
-‐
Dagger
public class BaseFragment extends Fragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Perform injection so that when this call returns all
// dependencies will be available for use.
((KitKatMachineApplication) getApplication()).inject(this); }
}!
• The
same
goes
for
the
Ac+vity.
• It
is
highly
customizable
– For
Instance:
It
is
possible
to
personalize
the
modules
that
we
want
to
inject
into
the
Ac+vity
(crea+ng
a
derivate
graph)
24
27. Injec+ng
other
stuff
-‐
Qualifiers
• It
is
also
possible
to
inject
Qualifiers:
-‐
Module:
@Provides @Named("app_version")
public String getAppVersionCode(Context context) {
return String.valueOf(getPackageInfo(context).versionCode);
}!
-‐
InjecSng:
!
@Inject @Named("app_version") String version;!
!
26
28. Injec+ng
other
stuff
-‐
RoboGuice
• With
RoboGuice
we
can
inject
views,
preferences,
fragments,
extras
and
resources:
@InjectView(R.id.myTextView) private TextView myTextView;
@InjectResource(R.string.app_name) private String appName;!
!
• We
also
can
inject
Context,
Inflater,
Services
and
some
other
Android
Objects.
– Check
out
DefaultRoboModule.java
for
more
informa+on
27
30. Side
by
side
RoboGuice
• Can
inject
dependencies
in
private
fields
• Method
Injec+on
supported
• Configure
Proguard
is
hard
(doable)
• Ready
to
inject
a
lot
of
Android
stuff
• It
uses
Guice
which
is
more
server
related
• Very
cool
framework
Dagger
• Method
Injec+on
not
supported…
for
now
• Faster.
In
a
big
app
it
can
reduce
the
startup
+me
in
a
few
seconds
• Configure
Proguard
is
a
pain
in
the
ass
• If
you
want
to
inject
Android
stuff
you
need
to
write
the
code
to
do
it
• It
forces
developers
to
write
a
bit
more
code
• Remember
that
it
generates
code!
• Very
cool
framework
29
31. Conclusions
• Dependency
injec+ons
allows
the
developer
to
spend
+me
on
the
important
parts
• It
makes
the
applica+on
more
modular
• It
helps
tes+ng
your
applica+on
• It
makes
your
code
less
like
spagheq,
ravioli,
lasagna
and
other
Italian
foods
• The
developer
needs
to
understand
the
DI
framework
• Easier
to
implement
at
the
beginning
than
at
the
end
• Very
cool
frameworks
:)
30