Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Android DI
Search
Daichi Furiya (Wasabeef)
September 16, 2014
Programming
9
1.3k
Android DI
AndroidでDIをしてみる
ButterKnife, Dagger
Daichi Furiya (Wasabeef)
September 16, 2014
Tweet
Share
More Decks by Daichi Furiya (Wasabeef)
See All by Daichi Furiya (Wasabeef)
DevFest Tokyo 2025 - Flutter のアプリアーキテクチャ現在地点
wasabeef
5
1.9k
About Flutter Architecture
wasabeef
1
250
2023 Flutter/Dart Summary
wasabeef
0
77
I/O Extended 2023 - Dart と Flutter の新機能
wasabeef
0
180
I/O Extended 2023 - Flutter 活用事例
wasabeef
10
3k
What it Takes to be a Flutter Developer
wasabeef
0
200
FlutterKaigi 2022 Keynote
wasabeef
1
610
Flutter Hooks を使ったアプリ開発 / App Development with the Flutter Hooks
wasabeef
2
1.4k
Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back on Flutter 2021 and for future app development.
wasabeef
4
2.2k
Other Decks in Programming
See All in Programming
バイブコーディング超えてバイブデプロイ〜CloudflareMCPで実現する、未来のアプリケーションデリバリー〜
azukiazusa1
2
660
CIを整備してメンテナンスを生成AIに任せる
hazumirr
0
140
DMMを支える決済基盤の技術的負債にどう立ち向かうか / Addressing Technical Debt in Payment Infrastructure
yoshiyoshifujii
4
510
GPUを計算資源として使おう!
primenumber
1
280
オンコール⼊⾨〜ページャーが鳴る前に、あなたが備えられること〜 / Before The Pager Rings
yktakaha4
2
1.1k
Rails Frontend Evolution: It Was a Setup All Along
skryukov
0
310
AI時代の『改訂新版 良いコード/悪いコードで学ぶ設計入門』 / ai-good-code-bad-code
minodriven
24
9.9k
なぜあなたのオブザーバビリティ導入は頓挫するのか
ryota_hnk
0
110
はじめてのWeb API体験 ー 飲食店検索アプリを作ろうー
akinko_0915
0
160
「次に何を学べばいいか分からない」あなたへ──若手エンジニアのための学習地図
panda_program
3
600
SwiftでMCPサーバーを作ろう!
giginet
PRO
2
180
AIのメモリー
watany
7
450
Featured
See All Featured
Practical Orchestrator
shlominoach
189
11k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.3k
Bash Introduction
62gerente
613
210k
Being A Developer After 40
akosma
90
590k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.4k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
5.9k
RailsConf 2023
tenderlove
30
1.2k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
Statistics for Hackers
jakevdp
799
220k
Six Lessons from altMBA
skipperchong
28
3.9k
Producing Creativity
orderedlist
PRO
346
40k
Transcript
Android Dependency Injection CyberAgent, Inc. ߱ େ
About Me Daichi Furiya @wasabeef_jp wasabeef http://wasabeef.jp
ݱࡏɺϑϧωΠςΟϒͷ ৽نΞϓϦΛ։ൃத
// 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'
// 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'
DI Libraries • Google/Guice • RoboGuice • AndroidAnnotations • Dagger
• Butter Knife
Butter Knife
ViewपΓͷ͓ܾ·ΓCodeΛ AnnotationΛར༻ͯ͠ੜ͢Δ View "injection" library for Android which uses annotation
processing to generate boilerplate code for you.
View Injection
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); } }
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); } }
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); ! ! } }
View Lists Injection @InjectViews({R.id.first_name, R.id.middle_name, R.id.last_name }) List<EditText> mNameViews;
ButterKnife.apply(mNameViews, View.ALPHA, 0); ButterKnife.apply
static final Action<View> DISABLE = new Action<>() { @Override public
void apply(View view, int index) { view.setEnabled(false); } } ! ! ButterKnife.apply(mNameViews, DISABLE); Custom Action
Listener Injection
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."); } }
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."); ! } }
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."); ! } }
Multiple OnClick @OnClick({ R.id.door1, R.id.door2, R.id.door3 }) public void pickDoor(DoorView
door) { // TODO Use.. }
Android Studio Plugin ! -> android-butterknife-zelezny
ButterKnife ·ͱΊ • ViewͷInjectionʹಛԽͯ͠Δ • ػೳ͕গͳ͍͚ͩʹɺγϯϓϧͰ͍͍͢
Square/Dagger
Guice ʁ • ͱͯීٴͯ͠Δ • ඪ४తͳInjectionͷػೳΛඋ͑ͯΔ • ॳظԽٴͼInjection͕͘ɺϝϞϦͷى ͖͍͢
Dagger (ObjectGraph) • ίϯύΠϧ࣌ݕূɿϞδϡʔϧͱೖΛݕূ ͢ΔΞϊςʔγϣϯϓϩηοα • ࣮ߦ࣌ʹɺϦϑϨΫγϣϯΛར༻͠ͳ͍ • ϝϞϦͷӨڹۃΘ͔ͣʹ͢Δ •
ViewͷInjectग़དྷͳ͍
Dagger ͷߏཁૉ
@Module + @Provides ґଘؔΛఏڙ͢ΔͨΊͷΈɾઃఆ
ObjectGraph ґଘؔཧͱΠϯδΣΫλ
@Inject ґଘؔΛཁٻ͢ΔͨΊͷΈ
@Module + @Provides ͷఆٛ
! 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(); } }
@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(); } }
@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(); } }
ObjectGraph + @Inject ͷఆٛ
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(); } }
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(); } }
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); ! ! } }
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); ! ! } }
ObjectGraph.plus
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); } }
ग़དྷͳ͍͜ͱ
! ! ! ! @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(); } ! /*****/ }
@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(); } }
! ! ! ! @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(); } ! /*****/ }
Google/Dagger
Square/Daggerͱͷҧ͍ ɾτϨʔαϏϦςΟ ɾ໌֬ͳAPI ɾύϑΥʔϚϯε্
None
DaggerͰԿ͕͍͔ͨ͠ʁ
Testable Android
@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()); } }
Android Studio Plugin ! ! -> dagger-intellij-plugin
Dagger ·ͱΊ • ৽ͨʹDI༻ͷઃܭΛਅʹߟ͑Δ • υΩϡϝϯτ͕গͳ͍ • ButterKnife, Retrofitͱซ༻͢Δͷ͕ྑ͍ •
Google/Dagger͕ग़ΔͷͰɺকདྷੑ༗Γ
ͬͺΓΞϊςʔγϣϯͩΑͶ @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
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ