Slide 1

Slide 1 text

Android Dependency Injection CyberAgent, Inc. ߱໼ େ஍

Slide 2

Slide 2 text

About Me Daichi Furiya @wasabeef_jp wasabeef http://wasabeef.jp

Slide 3

Slide 3 text

ݱࡏɺϑϧωΠςΟϒͷ ৽نΞϓϦΛ։ൃத

Slide 4

Slide 4 text

// Google compile 'com.android.support:support-v4:20.+' compile 'com.android.support:support-v13:20.+' compile 'com.android.support:recyclerview-v7:21.0.0-rc1' compile 'com.android.support:cardview-v7:21.0.0-rc1' compile 'com.google.android.gms:play-services:5.+' // Square compile 'com.squareup.retrofit:retrofit:1.6.+' compile 'com.squareup.okhttp:okhttp:2.0.+' compile ‘com.squareup.okhttp:okhttp-urlconnection:2.0.+’ compile 'com.squareup:otto:1.3.+' compile 'com.jakewharton.timber:timber:2.4.+' compile 'com.jakewharton:butterknife:5.1.+' compile 'com.squareup.dagger:dagger:1.2.+' compile 'com.squareup.dagger:dagger-compiler:1.2.+' // Image Loader compile 'com.github.bumptech.glide:glide:3.3.+'.2.+' // JSON compile 'com.fasterxml.jackson.core:jackson-core:2.2.+' compile 'com.fasterxml.jackson.core:jackson-databind:2.2.+' // UI compile 'com.github.ksoichiro:simplealertdialog:1.1.1@aar' compile 'com.commonsware.cwac:richedit:0.3.0' compile 'com.github.manuelpeinado.fadingactionbar:fadingactionbar:3.1.+' // Serialize compile 'org.parceler:parceler-api:0.2.+' provided 'org.parceler:parceler:0.2.+' compile 'com.github.satyan:sugar:1.4@aar' // Unit Test testCompile 'junit:junit:4.10' testCompile 'org.robolectric:robolectric:2.+' testCompile 'org.assertj:assertj-core:1.6.1'

Slide 5

Slide 5 text

// Google compile 'com.android.support:support-v4:20.+' compile 'com.android.support:support-v13:20.+' compile 'com.android.support:recyclerview-v7:21.0.0-rc1' compile 'com.android.support:cardview-v7:21.0.0-rc1' compile 'com.google.android.gms:play-services:5.+' // Square compile 'com.squareup.retrofit:retrofit:1.6.+' compile 'com.squareup.okhttp:okhttp:2.0.+' compile ‘com.squareup.okhttp:okhttp-urlconnection:2.0.+’ compile 'com.squareup:otto:1.3.+' compile 'com.jakewharton.timber:timber:2.4.+' compile 'com.jakewharton:butterknife:5.1.+' compile 'com.squareup.dagger:dagger:1.2.+' compile 'com.squareup.dagger:dagger-compiler:1.2.+' // Image Loader compile 'com.github.bumptech.glide:glide:3.3.+'.2.+' // JSON compile 'com.fasterxml.jackson.core:jackson-core:2.2.+' compile 'com.fasterxml.jackson.core:jackson-databind:2.2.+' // UI compile 'com.github.ksoichiro:simplealertdialog:1.1.1@aar' compile 'com.commonsware.cwac:richedit:0.3.0' compile 'com.github.manuelpeinado.fadingactionbar:fadingactionbar:3.1.+' // Serialize compile 'org.parceler:parceler-api:0.2.+' provided 'org.parceler:parceler:0.2.+' compile 'com.github.satyan:sugar:1.4@aar' // Unit Test testCompile 'junit:junit:4.10' testCompile 'org.robolectric:robolectric:2.+' testCompile 'org.assertj:assertj-core:1.6.1'

Slide 6

Slide 6 text

DI Libraries • Google/Guice • RoboGuice • AndroidAnnotations • Dagger • Butter Knife

Slide 7

Slide 7 text

Butter Knife

Slide 8

Slide 8 text

ViewपΓͷ͓ܾ·ΓCodeΛ AnnotationΛར༻ͯ͠ੜ੒͢Δ View "injection" library for Android which uses annotation processing to generate boilerplate code for you.

Slide 9

Slide 9 text

View Injection

Slide 10

Slide 10 text

public class ExampleActivity extends Activity { TextView mTitle; TextView mBody; TextView mFooter; ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ! mTitle = (TextView) findViewById(R.id.title); mSubTitle = (TextView) findViewById(R.id.body); mFooter = (TextView) findViewById(R.id.footer); } }

Slide 11

Slide 11 text

public class ExampleActivity extends Activity { @InjectView(R.id.title) TextView mTitle; @InjectView(R.id.subtitle) TextView mSubtitle; @InjectView(R.id.footer) TextView mFooter; ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ! mTitle = (TextView) findViewById(R.id.title); mSubTitle = (TextView) findViewById(R.id.body); mFooter = (TextView) findViewById(R.id.footer); } }

Slide 12

Slide 12 text

public class ExampleActivity extends Activity { @InjectView(R.id.title) TextView mTitle; @InjectView(R.id.subtitle) TextView mSubtitle; @InjectView(R.id.footer) TextView mFooter; ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ! ButterKnife.inject(this); ! ! } }

Slide 13

Slide 13 text

View Lists Injection @InjectViews({R.id.first_name, R.id.middle_name, R.id.last_name }) List mNameViews;

Slide 14

Slide 14 text

ButterKnife.apply(mNameViews, View.ALPHA, 0); ButterKnife.apply

Slide 15

Slide 15 text

static final Action DISABLE = new Action<>() { @Override public void apply(View view, int index) { view.setEnabled(false); } } ! ! ButterKnife.apply(mNameViews, DISABLE); Custom Action

Slide 16

Slide 16 text

Listener Injection

Slide 17

Slide 17 text

public class ExampleActivity extends Activity implements View.OnClickListener { ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ! findViewById(R.id.button).setOnClickListener(this); } ! @Override public void onClick(View v) { Button button = (Button) v; button.setText("clicked."); } }

Slide 18

Slide 18 text

public class ExampleActivity extends Activity { ! ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ! ! } ! @OnClick(R.id.submit) public void onClickSubmit(Button button) { button.setText(“clicked."); ! } }

Slide 19

Slide 19 text

public class ExampleActivity extends Activity { ! ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ! ButterKnife.inject(this); } ! @OnClick(R.id.submit) public void onClickSubmit(Button button) { button.setText(“clicked."); ! } }

Slide 20

Slide 20 text

Multiple OnClick @OnClick({ R.id.door1, R.id.door2, R.id.door3 }) public void pickDoor(DoorView door) { // TODO Use.. }

Slide 21

Slide 21 text

Android Studio Plugin ! -> android-butterknife-zelezny

Slide 22

Slide 22 text

ButterKnife ·ͱΊ • ViewͷInjectionʹಛԽͯ͠Δ • ػೳ͕গͳ͍͚ͩʹɺγϯϓϧͰ࢖͍΍͍͢

Slide 23

Slide 23 text

Square/Dagger

Slide 24

Slide 24 text

Guice ͸ʁ • ͱͯ΋ීٴͯ͠Δ • ඪ४తͳInjectionͷػೳΛඋ͑ͯΔ • ॳظԽٴͼInjection͕஗͘ɺϝϞϦͷ໰୊ى ͖΍͍͢

Slide 25

Slide 25 text

Dagger (ObjectGraph) • ίϯύΠϧ࣌ݕূɿϞδϡʔϧͱ஫ೖΛݕূ ͢ΔΞϊςʔγϣϯϓϩηοα • ࣮ߦ࣌ʹ͸ɺϦϑϨΫγϣϯΛར༻͠ͳ͍ • ϝϞϦ΁ͷӨڹ͸ۃΘ͔ͣʹ͢Δ • ViewͷInject͸ग़དྷͳ͍

Slide 26

Slide 26 text

Dagger ͷߏ੒ཁૉ

Slide 27

Slide 27 text

@Module + @Provides ґଘؔ܎Λఏڙ͢ΔͨΊͷ࢓૊Έɾઃఆ

Slide 28

Slide 28 text

ObjectGraph ґଘؔ܎؅ཧͱΠϯδΣΫλ

Slide 29

Slide 29 text

@Inject ґଘؔ܎Λཁٻ͢ΔͨΊͷ࢓૊Έ

Slide 30

Slide 30 text

@Module + @Provides ͷఆٛ

Slide 31

Slide 31 text

! public class ApiModule { ! public RestAdapter provideRestAdapter(OkHttpClient client) { return new RestAdapter.Builder() .setEndpoint(“http://wasabeef.jp”) .setClient(new OkClient(client)) .build(); } ! ! public OkHttpClient provideOkHttpClient() { return new OkHttpClient(); } }

Slide 32

Slide 32 text

@Module( injects = ExampleActivity.java ) public class ApiModule { ! public RestAdapter provideRestAdapter(OkHttpClient client) { return new RestAdapter.Builder() .setEndpoint(“http://wasabeef.jp”) .setClient(new OkClient(client)) .build(); } ! ! public OkHttpClient provideOkHttpClient() { return new OkHttpClient(); } }

Slide 33

Slide 33 text

@Module( injects = ExampleActivity.java ) public class ApiModule { @Provides @Singleton public RestAdapter provideRestAdapter(OkHttpClient client) { return new RestAdapter.Builder() .setEndpoint(“http://wasabeef.jp”) .setClient(new OkClient(client)) .build(); } ! @Provides @Singleton public OkHttpClient provideOkHttpClient() { return new OkHttpClient(); } }

Slide 34

Slide 34 text

ObjectGraph + @Inject ͷఆٛ

Slide 35

Slide 35 text

public class ExampleActivity extends Activity { ! ! RestAdapter mRestAdapter; ! @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ! mRestAdapter = new RestAdapter.Builder() .setEndpoint(“http://wasabeef.jp”) .setClient(new OkClient(new OkHttpClient())) .build(); } }

Slide 36

Slide 36 text

public class ExampleActivity extends Activity { private ObjectGraph mObjectGraph; ! RestAdapter mRestAdapter; ! @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ! mRestAdapter = new RestAdapter.Builder() .setEndpoint(“http://wasabeef.jp”) .setClient(new OkClient(new OkHttpClient())) .build(); } }

Slide 37

Slide 37 text

public class ExampleActivity extends Activity { private ObjectGraph mObjectGraph; ! RestAdapter mRestAdapter; ! @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ! mObjectGraph = ObjectGraph.create(new ApiModule()); mObjectGraph.inject(this); ! ! } }

Slide 38

Slide 38 text

public class ExampleActivity extends Activity { private ObjectGraph mObjectGraph; ! @Inject RestAdapter mRestAdapter; ! @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ! mObjectGraph = ObjectGraph.create(new ApiModule()); mObjectGraph.inject(this); ! ! } }

Slide 39

Slide 39 text

ObjectGraph.plus

Slide 40

Slide 40 text

public class SignUpActivity extends Activity { private ObjectGraph mObjectGraph; ! @Inject RestAdapter mRestAdapter; ! @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ! ExampleApp app = (ExampleApp) getApplication(); mObjectGraph = app.getObjectGraph(); mObjectGraph.plus(new SignUpModule()); mObjectGraph.inject(this); } }

Slide 41

Slide 41 text

ग़དྷͳ͍͜ͱ

Slide 42

Slide 42 text

! ! ! ! @Module( injects = ExampleActivity.java ) public class ApiModule { @Provides @Singleton public RestAdapter provideRestAdapter(OkHttpClient client) { return new RestAdapter.Builder() .setEndpoint(“http://wasabeef.jp”) .setClient(new OkClient(client)) .build(); } ! /*****/ }

Slide 43

Slide 43 text

@Module( injects = { ExampleActivity.java, ExampleLoginActivity.java, ExampleWebActivity.java, ExampleImageActivity.java, ExampleCameraActivity.java } ) public class ApiModule { @Provides @Singleton public RestAdapter provideRestAdapter(OkHttpClient client) { return new RestAdapter.Builder() .setEndpoint(“http://wasabeef.jp”) .setClient(new OkClient(client)) .build(); } }

Slide 44

Slide 44 text

! ! ! ! @Module( injects = BaseActivity.java ) public class ApiModule { @Provides @Singleton public RestAdapter provideRestAdapter(OkHttpClient client) { return new RestAdapter.Builder() .setEndpoint(“http://wasabeef.jp”) .setClient(new OkClient(client)) .build(); } ! /*****/ }

Slide 45

Slide 45 text

Google/Dagger

Slide 46

Slide 46 text

Square/Daggerͱͷҧ͍ ɾτϨʔαϏϦςΟ ɾ໌֬ͳAPI ɾύϑΥʔϚϯε޲্

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

DaggerͰԿ͕͍͔ͨ͠ʁ

Slide 49

Slide 49 text

Testable Android

Slide 50

Slide 50 text

@RunWith(RobolectricTestRunner.class) public class Test { ! @Inject RestAdapter mRestAdapter; ! @Module( includes = ApiModule.class, injects = { TestActivity.class }, overrides = true, complete = false ) class TestApiModule { @Provides @Singleton public RestAdapter provideRestAdapter(OkHttpClient okHttpClient) { return new RestAdapter.Builder() // .setEndpoint(“http://127.0.0.1:8080”) .setClient(new OkClient(client)) .build(); } ! @Provides @Singleton public Client provideOkHttpClient() { return new LocalJsonClient(Robolectric.application.getApplicationContext()); } }

Slide 51

Slide 51 text

Android Studio Plugin ! ! -> dagger-intellij-plugin

Slide 52

Slide 52 text

Dagger ·ͱΊ • ৽ͨʹDI༻ͷઃܭΛਅ݋ʹߟ͑Δ • υΩϡϝϯτ͕গͳ͍ • ButterKnife, Retrofitͱซ༻͢Δͷ͕ྑ͍ • Google/Dagger͕ग़ΔͷͰɺকདྷੑ͸༗Γ

Slide 53

Slide 53 text

΍ͬͺΓΞϊςʔγϣϯͩΑͶ @Parcel @JsonInclude @JsonValue @JsonCreator @Module @Singleton @Provides @Inject @Subscribe @DrawableRes @StringRes @OnClick @InjectView @IdRes @POST @Path @Body @GET @Query @PUT @Multipart @Nullable @NonNull @Override @SuppressLint @TargetApi

Slide 54

Slide 54 text

͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ