Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Android DI
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Daichi Furiya (Wasabeef)
September 16, 2014
Programming
1.4k
9
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Android DI
AndroidでDIをしてみる
ButterKnife, Dagger
Daichi Furiya (Wasabeef)
September 16, 2014
More Decks by Daichi Furiya (Wasabeef)
See All by Daichi Furiya (Wasabeef)
DevFest Tokyo 2025 - Flutter のアプリアーキテクチャ現在地点
wasabeef
6
2.9k
About Flutter Architecture
wasabeef
1
330
2023 Flutter/Dart Summary
wasabeef
0
140
I/O Extended 2023 - Dart と Flutter の新機能
wasabeef
0
250
I/O Extended 2023 - Flutter 活用事例
wasabeef
10
3.1k
What it Takes to be a Flutter Developer
wasabeef
0
270
FlutterKaigi 2022 Keynote
wasabeef
1
760
Flutter Hooks を使ったアプリ開発 / App Development with the Flutter Hooks
wasabeef
2
1.6k
Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back on Flutter 2021 and for future app development.
wasabeef
4
2.3k
Other Decks in Programming
See All in Programming
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
170
setup-vp GitLab対応の裏側
naokihaba
0
110
新卒PdEのリアル
ryu1013
1
500
SONY CISC-NEWS NWS-1750 + NWB-225 フレームバッファの NetBSD/news68k ドライバ実装 / OSC2026Hiroshima
tsutsui
0
120
Heart of Swift Concurrency
koher
0
890
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
180
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
1.6k
MVNOの申込からeSIM開通までをiOSアプリでつなぐ- 本人確認・MNP・通信事業者基盤をまたぐ実装
satotakeshi
0
430
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
220
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
1
150
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
480
JPUG勉強会 OSSデータベースの内部構造を理解しよう(第2回)
oga5
0
260
Featured
See All Featured
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Exploring anti-patterns in Rails
aemeredith
4
510
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
490
Practical Orchestrator
shlominoach
192
12k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Fireside Chat
paigeccino
43
4k
What's in a price? How to price your products and services
michaelherold
247
13k
Are puppies a ranking factor?
jonoalderson
2
3.9k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
Optimizing for Happiness
mojombo
378
71k
Faster Mobile Websites
deanohume
310
32k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
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
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ