Sword fighting with Dagger GDG-NYC Jan 2016

44
Sword Fighting with Dagger Mike Nakhimovich Android Engineer NY Times

Transcript of Sword fighting with Dagger GDG-NYC Jan 2016

Page 1: Sword fighting with Dagger GDG-NYC Jan 2016

Sword Fighting with DaggerMike Nakhimovich

Android Engineer NY Times

Page 2: Sword fighting with Dagger GDG-NYC Jan 2016

What is Dagger?

Dagger offers an alternative way to instantiate

and manage your objects through

Dependency Injection

Dagger 2 open sourced by Google

Dagger 1 – Square

Guice – Google (Dagger v.0)

Page 3: Sword fighting with Dagger GDG-NYC Jan 2016

Compile Time Annotation Processing (Fast)

Superpowers

Lazy

Singleton

Provider

Object Scoping (Application/Session/Activity)

Why Dagger?

Page 4: Sword fighting with Dagger GDG-NYC Jan 2016

In the Olden Days...

Page 5: Sword fighting with Dagger GDG-NYC Jan 2016

Old Waypublic class RedditView {

private RedditPresenter presenter;

public RedditView(...) {

Gson gson = new GsonBuilder().create();

RedditApi redditApi = new Retrofit.Builder()

.addConverterFactory(GsonConverterFactory.create(gson))

.build().create(RedditApi.class);

RedditDAO redditDAO = new RedditDAO(redditApi);

presenter=new RedditPresenter(redditDAO);

}

Page 6: Sword fighting with Dagger GDG-NYC Jan 2016

Externalize Object Creation

Page 7: Sword fighting with Dagger GDG-NYC Jan 2016

@Provides

Gson provideGson() {

}

Create a Provider

return new GsonBuilder().create();

}

Page 8: Sword fighting with Dagger GDG-NYC Jan 2016

ModulesA Module is a part of your application that provides

implementations.

@Module public class DataModule {

}

@Provides Gson provideGson() {

return gsonBuilder.create();}

Page 9: Sword fighting with Dagger GDG-NYC Jan 2016

Dependencies@Provides methods can have their own dependencies

@Provides

RedditApi provideRedditApi(Gson gson) {

return new Retrofit.Builder()

.addConverterFactory(

GsonConverterFactory.create(gson))

.build().create(RedditApi.class);

}

Page 10: Sword fighting with Dagger GDG-NYC Jan 2016

Provides not necessaryYou can also annotate constructors directly to register

public class RedditDAO {

@Inject

public RedditDAO(RedditApi api) {

super();

}

}

Provided by Module

Page 11: Sword fighting with Dagger GDG-NYC Jan 2016

Consuming Dependencies

Page 12: Sword fighting with Dagger GDG-NYC Jan 2016

ComponentsA component is a part of your application that consumes

functionality. Built from Module(s)

@Component( modules = {DataModule.class})

public interface AppComponent {

void inject(RedditView a);

}

Page 13: Sword fighting with Dagger GDG-NYC Jan 2016

Register with ComponentActivities/Services/Views register with an instance of a

component

public RedditView(Context context) {

getComponent().inject(this);

}

Page 14: Sword fighting with Dagger GDG-NYC Jan 2016

Injection Fun

Now you can inject any dependencies

managed by the component.

As a field As a Constructor Param

Page 15: Sword fighting with Dagger GDG-NYC Jan 2016

Instantiating Dependencies Old WayRedditPresenter presenter;

public RedditView(Context context) {

super(context);

Gson gson = new GsonBuilder().create();

RedditApi redditApi = new Retrofit.Builder()

.addConverterFactory(GsonConverterFactory.create(gson))

.build()

.create(RedditApi.class);

RedditDAO redditDAO = new RedditDAO(redditApi);

presenter=new RedditPresenter(redditDAO);

}

Page 16: Sword fighting with Dagger GDG-NYC Jan 2016

Once RedditView registers itself with a component,

Dagger will satisfy all managed dependencies with

@Inject annotations

@Inject RedditPresenter presenter;

public RedditView(...) {getComponent().inject(this);

}

Instantiating Dependencies Dagger Way

Page 17: Sword fighting with Dagger GDG-NYC Jan 2016

How does Dagger do it?A static DaggerAppComponent.builder() call creates a Builder instance;

Builder creates an DaggerAppComponent instance;

DaggerAppComponent creates a RedditView_MembersInjector instance;

RedditView_MembersInjectorr uses RedditPresenter_Factory to

instantiate RedditPresenter and injects it into RedditView.

Just as fast as hand written code but with fewer errors

Page 18: Sword fighting with Dagger GDG-NYC Jan 2016

Generated Code@Generated("dagger.internal.codegen.ComponentProcessor")public final class RedditPresenter_Factory implements Factory<RedditPresenter> {private final MembersInjector<RedditPresenter> membersInjector;

public RedditPresenter_Factory(MembersInjector<RedditPresenter> membersInjector) { assert membersInjector != null;this.membersInjector = membersInjector;

}

@Overridepublic RedditPresenter get() { RedditPresenter instance = new RedditPresenter();membersInjector.injectMembers(instance);return instance;

}

public static Factory<RedditPresenter> create(MembersInjector<RedditPresenter> membersInjector) { return new RedditPresenter_Factory(membersInjector);

}}

Page 19: Sword fighting with Dagger GDG-NYC Jan 2016

Dependency ChainThe Presenter has its own dependency

public class RedditPresenter {

@Inject RedditDAO dao;

}

Page 20: Sword fighting with Dagger GDG-NYC Jan 2016

Dependency ChainWhich has its own dependency

public class RedditDAO {

private final RedditApi api;

@Inject

public RedditDAO(RedditApi api) {

this.api = api;

}

Page 21: Sword fighting with Dagger GDG-NYC Jan 2016

Dagger Eliminates “Passing Through” Constructor Arguments

Page 22: Sword fighting with Dagger GDG-NYC Jan 2016

Old WayRedditPresenter presenter;

public RedditView(...) {

super(context);

Gson gson = new GsonBuilder().create();

RedditApi redditApi = new Retrofit.Builder()

.addConverterFactory(GsonConverterFactory.create(gson))

.build()

.create(RedditApi.class);

RedditDAO redditDAO = new RedditDAO(redditApi);

presenter=new RedditPresenter(redditDAO);

}

Page 23: Sword fighting with Dagger GDG-NYC Jan 2016

Dagger Eliminates “Passing Through” Constructor Arguments

Dagger Way:Inject ONLY the dependencies each

object needs

Page 24: Sword fighting with Dagger GDG-NYC Jan 2016

Type of Injections

Dagger has a few types of injection:

Direct

Lazy

Provider

Page 25: Sword fighting with Dagger GDG-NYC Jan 2016

Direct

When instance is created also create the

dependency.

public class RedditPresenter {

@Inject RedditDAO dao;

}

Page 26: Sword fighting with Dagger GDG-NYC Jan 2016

Lazy

Do not instantiate until .get() is called.

public class RedditPresenter {

@Inject Lazy<RedditDAO> dao;

}

Useful to keep startup time down

Page 27: Sword fighting with Dagger GDG-NYC Jan 2016

ProviderProvider<T> allows you to inject multiple

instances of same object by calling .get()

public class RedditPresenter {

@Inject Provider<RedditDAO>

dao;

}

Page 28: Sword fighting with Dagger GDG-NYC Jan 2016

Singletons Old Waypublic class MainActivity extends Activity {

SharedPreferences pref;

Gson gson;

ServerAPI api;

onCreate(...) {

MyApp app = (MyApp)getContext().getApplicationContext();

pref = app.getSharedPreferences();

gson = app.getGson();

api = app.getApi();

Why is MYApp managing all singletons? :-(

Page 29: Sword fighting with Dagger GDG-NYC Jan 2016

Singletons Dagger Way

Define objects to be Singletons

@Singleton @Provides

Gson provideGson() {

return gsonBuilder.create();

}

Page 30: Sword fighting with Dagger GDG-NYC Jan 2016

Singletons Dagger Way

Define objects to be Singletons

@Singleton

public class RedditDAO{

@Inject

public RedditDAO() {

}

Page 31: Sword fighting with Dagger GDG-NYC Jan 2016

Singleton Management

@Singleton = Single instance per Component

@Singleton

@Component( modules = {DataModule.class})

public interface AppComponent {

void inject(RedditView a);

}

Page 32: Sword fighting with Dagger GDG-NYC Jan 2016

Scopes

Singleton is a scope annotation

@Scope

@Documented

@Retention(RUNTIME)

public @interface Singleton {}

We can create custom scope annotations

Page 33: Sword fighting with Dagger GDG-NYC Jan 2016

Subcomponent

Creating a Subcomponent with a scope

@Subcomponent(modules = {

ActivityModule.class})

@ActivityScope

public interface ActivityComponent

Page 34: Sword fighting with Dagger GDG-NYC Jan 2016

Subcomponent

plussing your component into another

component will inherit all objects

Page 35: Sword fighting with Dagger GDG-NYC Jan 2016

Injecting ActivitiesComponents scoped (recreated) with each activity allows us to do silly things

like injecting an activity into scoped objects:

@ScopeActivity

public class Toaster {

@Inject Activity activity;

private static void showToast() {

Toast.makeText(activity, message).show();

}}

Page 36: Sword fighting with Dagger GDG-NYC Jan 2016

Inject a Scoped Object@Inject

SnackbarUtil snackbarUtil;

there’s no need to pass activity into presenter and then

into the SnackBarMaker

objects can independently satisfy their own

dependencies.

Page 37: Sword fighting with Dagger GDG-NYC Jan 2016

Scoped If you try to inject something into an object with a

different scope, Dagger with give compilation error.

Scopes let objects “share” the same instance of anything in

the scope. ToolbarPresenters, IntentHolders etc.

Page 38: Sword fighting with Dagger GDG-NYC Jan 2016

Scopes cont’dScopes empower “activity singletons” that you

can share and not worry about reinstantiating

for each activity.

Page 39: Sword fighting with Dagger GDG-NYC Jan 2016

Dagger @ The New York Times

How we leveraged scope at The Times:

Inject activity intents into fragments 2 layers down

Create a toolbar presenter, each activity and its views get

access to the same presenter

Inject an alerthelper/snackbar util that can show alerts.

Page 40: Sword fighting with Dagger GDG-NYC Jan 2016

Dagger lets us decompose our activities

Page 41: Sword fighting with Dagger GDG-NYC Jan 2016

Dagger @ The New York TimesWe can inject something that is being provided

by a module in library project.

A/B Module within A/B Project provides

injectable A/B manager

API project owns API module etc. Main Project

creates a component using all the modules

Page 42: Sword fighting with Dagger GDG-NYC Jan 2016

Dagger @ The New York TimesWe can inject different implementations for

same interface spread across build variants

using a FlavorModule.

Amazon Flavor provides module with Amazon

Messaging

Google Flavor provides module with Google

Messaging

Page 43: Sword fighting with Dagger GDG-NYC Jan 2016

Sample Project

https://github.com/digitalbuddha/StoreDemo

Page 44: Sword fighting with Dagger GDG-NYC Jan 2016

Come work with me

http://developers.nytimes.com/careers