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)
About Flutter Architecture
wasabeef
0
160
2023 Flutter/Dart Summary
wasabeef
0
45
I/O Extended 2023 - Dart と Flutter の新機能
wasabeef
0
140
I/O Extended 2023 - Flutter 活用事例
wasabeef
11
2.7k
What it Takes to be a Flutter Developer
wasabeef
0
160
FlutterKaigi 2022 Keynote
wasabeef
1
550
Flutter Hooks を使ったアプリ開発 / App Development with the Flutter Hooks
wasabeef
2
1.3k
Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back on Flutter 2021 and for future app development.
wasabeef
4
2.1k
Flutter Hooks, sometimes Jetpack Compose
wasabeef
3
1.8k
Other Decks in Programming
See All in Programming
CSC509 Lecture 12
javiergs
PRO
0
160
AWS Lambdaから始まった Serverlessの「熱」とキャリアパス / It started with AWS Lambda Serverless “fever” and career path
seike460
PRO
1
260
役立つログに取り組もう
irof
28
9.6k
【Kaigi on Rails 2024】YOUTRUST スポンサーLT
krpk1900
1
330
A Journey of Contribution and Collaboration in Open Source
ivargrimstad
0
910
AWS IaCの注目アップデート 2024年10月版
konokenj
3
3.3k
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
110
ヤプリ新卒SREの オンボーディング
masaki12
0
130
Better Code Design in PHP
afilina
PRO
0
130
카카오페이는 어떻게 수천만 결제를 처리할까? 우아한 결제 분산락 노하우
kakao
PRO
0
110
C++でシェーダを書く
fadis
6
4.1k
Why Jakarta EE Matters to Spring - and Vice Versa
ivargrimstad
0
1.1k
Featured
See All Featured
Embracing the Ebb and Flow
colly
84
4.5k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Music & Morning Musume
bryan
46
6.2k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.8k
Designing Experiences People Love
moore
138
23k
Intergalactic Javascript Robots from Outer Space
tanoku
269
27k
The Power of CSS Pseudo Elements
geoffreycrofte
73
5.3k
What's in a price? How to price your products and services
michaelherold
243
12k
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
RailsConf 2023
tenderlove
29
900
A better future with KSS
kneath
238
17k
Docker and Python
trallard
40
3.1k
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
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ