Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android DI

Android DI

AndroidでDIをしてみる
ButterKnife, Dagger

6dd0483f1353a4a359e92633cfd65c64?s=128

Daichi Furiya (Wasabeef)

September 16, 2014
Tweet

Transcript

  1. Android Dependency Injection CyberAgent, Inc. ߱໼ େ஍

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

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

  4. // 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'
  5. // 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'
  6. DI Libraries • Google/Guice • RoboGuice • AndroidAnnotations • Dagger

    • Butter Knife
  7. Butter Knife

  8. ViewपΓͷ͓ܾ·ΓCodeΛ AnnotationΛར༻ͯ͠ੜ੒͢Δ View "injection" library for Android which uses annotation

    processing to generate boilerplate code for you.
  9. View Injection

  10. 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); } }
  11. 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); } }
  12. 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); ! ! } }
  13. View Lists Injection @InjectViews({R.id.first_name, R.id.middle_name, R.id.last_name }) List<EditText> mNameViews;

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

  15. static final Action<View> DISABLE = new Action<>() { @Override public

    void apply(View view, int index) { view.setEnabled(false); } } ! ! ButterKnife.apply(mNameViews, DISABLE); Custom Action
  16. Listener Injection

  17. 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."); } }
  18. 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."); ! } }
  19. 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."); ! } }
  20. Multiple OnClick @OnClick({ R.id.door1, R.id.door2, R.id.door3 }) public void pickDoor(DoorView

    door) { // TODO Use.. }
  21. Android Studio Plugin ! -> android-butterknife-zelezny

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

  23. Square/Dagger

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

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

    ViewͷInject͸ग़དྷͳ͍
  26. Dagger ͷߏ੒ཁૉ

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

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

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

  30. @Module + @Provides ͷఆٛ

  31. ! 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(); } }
  32. @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(); } }
  33. @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(); } }
  34. ObjectGraph + @Inject ͷఆٛ

  35. 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(); } }
  36. 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(); } }
  37. 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); ! ! } }
  38. 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); ! ! } }
  39. ObjectGraph.plus

  40. 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); } }
  41. ग़དྷͳ͍͜ͱ

  42. ! ! ! ! @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(); } ! /*****/ }
  43. @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(); } }
  44. ! ! ! ! @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(); } ! /*****/ }
  45. Google/Dagger

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

  47. None
  48. DaggerͰԿ͕͍͔ͨ͠ʁ

  49. Testable Android

  50. @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()); } }
  51. Android Studio Plugin ! ! -> dagger-intellij-plugin

  52. Dagger ·ͱΊ • ৽ͨʹDI༻ͷઃܭΛਅ݋ʹߟ͑Δ • υΩϡϝϯτ͕গͳ͍ • ButterKnife, Retrofitͱซ༻͢Δͷ͕ྑ͍ •

    Google/Dagger͕ग़ΔͷͰɺকདྷੑ͸༗Γ
  53. ΍ͬͺΓΞϊςʔγϣϯͩΑͶ @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
  54. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ