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.4k
About Flutter Architecture
wasabeef
1
210
2023 Flutter/Dart Summary
wasabeef
0
57
I/O Extended 2023 - Dart と Flutter の新機能
wasabeef
0
160
I/O Extended 2023 - Flutter 活用事例
wasabeef
10
2.9k
What it Takes to be a Flutter Developer
wasabeef
0
180
FlutterKaigi 2022 Keynote
wasabeef
1
580
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.1k
Other Decks in Programming
See All in Programming
CSS Linter による Baseline サポートの仕組み
ryo_manba
1
160
「個人開発マネタイズ大全」が教えてくれたこと
bani24884
1
290
複数のAWSアカウントから横断で 利用する Lambda Authorizer の作り方
tc3jp
0
130
Drawing Heighway’s Dragon- Recursive Function Rewrite- From Imperative Style in Pascal 64 To Functional Style in Scala 3
philipschwarz
PRO
0
150
1年目の私に伝えたい!テストコードを怖がらなくなるためのヒント/Tips for not being afraid of test code
push_gawa
1
650
コードを読んで理解するko build
bells17
1
120
ML.NETで始める機械学習
ymd65536
0
240
Jakarta EE meets AI
ivargrimstad
0
630
TCAを用いたAmebaのリアーキテクチャ
dazy
0
220
dbt Pythonモデルで実現するSnowflake活用術
trsnium
0
270
Webフレームワークとともに利用するWeb components / JSConf.jp おかわり
spring_raining
1
130
pylint custom ruleで始めるレビュー自動化
shogoujiie
0
160
Featured
See All Featured
RailsConf 2023
tenderlove
29
1k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Code Review Best Practice
trishagee
67
18k
A Modern Web Designer's Workflow
chriscoyier
693
190k
BBQ
matthewcrist
87
9.5k
Documentation Writing (for coders)
carmenintech
68
4.6k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
11
1.3k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
227
22k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7.1k
Agile that works and the tools we love
rasmusluckow
328
21k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
100
18k
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
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ