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 Dependencies You Can Depend On
Search
Daniel Lew
March 21, 2015
Programming
830
14
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Android Dependencies You Can Depend On
Daniel Lew
March 21, 2015
More Decks by Daniel Lew
See All by Daniel Lew
What the fuck are passkeys and why are they everywhere now?
dlew
1
63
How to Use Computers (Privately!)
dlew
0
110
Finding Meaningful, Mission-Driven Work
dlew
0
210
Things Maybe You Don't Know as a Newer Developer
dlew
1
160
Maintaining Software Correctness
dlew
4
1.1k
Grokking Coroutines (MinneBar)
dlew
5
710
ClimateChangeTech.pdf
dlew
0
180
What Tech Can Do About Climate Change
dlew
0
700
Grokking Coroutines
dlew
5
1.4k
Other Decks in Programming
See All in Programming
freeeにおけるEvalsの実践例の紹介
freee
PRO
0
130
Claude CodeとAgentCore Gatewayを繋ぐ際の認証認可 / Authentication and authorization when connecting Claude Code with AgentCore Gateway
har1101
2
340
Built Our Own Background Agent at LayerX
layerx
PRO
10
5.8k
まずはプロンプトガイドを読もう、話はそれからだ
kiakiraki
1
150
AWS DevOps AgentのAzure接続機能を検証して見えた活用法/Use Cases Verified for the AWS DevOps Agent's Azure Connectivity Feature
masakiokuda
1
250
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
240
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.8k
これって Effect でできたのでは? / TSKaigi Mashup Kansai #2
susisu
0
250
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
1.1k
Android CLI
fornewid
0
230
引き算の組織 ― アウトカムとAIに全振りするために辞めたこと ― / Organization by Subtraction
hirokiyamamoto14
PRO
0
260
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
19k
Featured
See All Featured
BBQ
matthewcrist
89
10k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
250
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
420
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3k
Paper Plane
katiecoart
PRO
2
53k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
270
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
630
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
The SEO identity crisis: Don't let AI make you average
varn
0
530
Why Our Code Smells
bkeepers
PRO
340
58k
Transcript
Android Dependencies You Can Depend On Dan Lew 3/21/2015
Why Libraries? • Stand on the shoulders of giants •
Hit the ground running • Easier than ever to use
Adding Libraries repositories { jcenter() } dependencies { compile
'com.squareup.retrofit:retrofit:1.9.0' }
Which Libraries?
My Basic Stack • Retrofit • GSON • Picasso •
OkHttp • Dagger • RxJava
Retrofit • …Because a lot of people use REST •
…Because REST is easy to understand
Example API http://company.com/api/public/cards?id=someId
Define an Interface http://company.com/api/public/cards?id=someId public interface MyService { @GET("/api/{visibility}/cards")
List<Card> getCards(@Path("visibility") String visibility, @Query("id") String id); }
Create a RestAdapter RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("http://company.com") .build();
MyService service = restAdapter.create(MyService.class);
Use the service List<Card> cards = service.getCards("public", "someId");
GSON • …Because many REST APIs use JSON
JSON vs. Object • JSON { "id": "someId", "data": "Some
data" } • Class public class Card { private String id; private String data; }
Without GSON String jsonStr = /* …what we had from
before… */; try { JSONObject jsonObject = new JSONObject(jsonStr); String id = jsonObject.getString("id"); String data = jsonObject.getString("data"); Card card = new Card(id, data); } catch (JSONException e) { e.printStackTrace(); }
With GSON String jsonStr = /* ...whatever you get from
Retrofit... */; Gson gson = new Gson(); Card card = gson.fromJson(jsonStr, Card.class);
Customizable • Can handle differently named fields: public class Card
{ @SerializedName("theId") private String id; @SerializedName("theData") private String data; } • Custom deserializers (type adapters)
Retrofit with GSON RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("http://company.com") .setConverter(new
GsonConverter(new Gson())) .build(); MyService service = restAdapter.create(MyService.class);
Picasso • Easy image loading Picasso.with(this) .load("http://path.to/image.png") .into(someImageView);
Picasso Options Picasso.with(this) .load("http://path.to/image.png") .placeholder(R.drawable.placeholder) .centerCrop() .into(someImageView);
OkHttp • Consistent HTTP implementation • Better HTTP implementation •
Easier HTTP implementation • Drives other libraries
OkHttp + Retrofit • Add client to RestAdapter RestAdapter restAdapter
= new RestAdapter.Builder() .setEndpoint("http://company.com") .setConverter(new GsonConverter(new Gson())) .setClient(new OkClient()) .build();
OkHttp + Picasso Picasso picasso = new Picasso.Builder() .downloader(new OkHttpDownloader())
.build(); picasso.load("http://path.to/image.png") .into(someImageView);
Dagger • Dependency injection! • …What does that really mean?
• …Why do you want it?
Components • RestAdapter • Gson • Picasso • OkHttp •
…All intertwined
BAD • DO NOT create new instances each time! RestAdapter
restAdapter = new RestAdapter.Builder() .setEndpoint("http://company.com") .setConverter(new GsonConverter(new Gson())) .setClient(new OkClient()) .build(); MyService service = restAdapter.create(MyService.class); Picasso picasso = new Picasso.Builder() .downloader(new OkHttpDownloader()).build();
Solving the Bad • Problem: Need to cache components •
Solution: static singletons!
It is now impossible to test most of your code
Solution Dependency injection!
It’s Not Complex • Without dependency injection public class SomeClass
{ private SomeService service; public SomeClass() { this.service = new SomeService(); } } • With dependency injection public class SomeClass { private SomeService service; public SomeClass(SomeService service) { this.service = service; } }
Unfortunately… • Passing around dependencies is a PITA! • Dagger:
Handles busywork for you
Dagger Modules @Module public class AppModule { @Provides @Singleton
Gson provideGson() { return new Gson(); } @Provides @Singleton Client provideClient() { return new OkClient(); } @Provides @Singleton RestAdapter provideRestAdapter(Gson gson, Client client) { return new RestAdapter.Builder() .setConverter(new GsonConverter(gson)) .setClient(client) .build(); } @Provides @Singleton MyService provideMyService(RestAdapter restAdapter) { return restAdapter.create(MyService.class); } }
Injecting Modules public class SomeClass { @Inject MyService myService;
public SomeClass() { // In real life, ObjectGraph should be reused ObjectGraph objectGraph = ObjectGraph.create(new AppModule()); objectGraph.inject(this); } }
RxJava • Reactive framework • Less coding • Easy error
handling • Easy concurrency • Just plain fun • …But not easy to understand at first
Observer Pattern Observable.just("1", "2", "3") .subscribe(new Action1<String>() { @Override public
void call(String s) { System.out.println(s); } });
Operators Observable.just("1", "2", "3") .map(new Func1<String, String>() { @Override public
String call(String s) { return "item: " + s; } }) .subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println(s); } });
Schedulers Observable.just("1", "2", "3") .map(new Func1<String, String>() { @Override public
String call(String s) { return "item: " + s; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println(s); } });
Error Handling Observable.just("1", "2", "3") .map(new Func1<String, String>() { @Override
public String call(String s) { return "item: " + s; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( new Action1<String>() { @Override public void call(String s) { System.out.println(s); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { System.out.println("Something went wrong!"); } });
u2020 • Great sample for (most) of basic stack •
https://github.com/JakeWharton/u2020/
Alternatives • Everything has alternatives • Impact, not implementation •
Weigh pros/cons
Development Libraries
Stetho • Debug bridge on Chrome
Stetho • Debug bridge on Chrome
Hugo • Before: public void doSomething(String input) { Log.i("SomeTagYouMadeUp", "doSomething("
+ input + ")"); // Shockingly, this does something Log.i("SomeTagYouMadeUp", "doSomething finished"); } • After: @DebugLog public void doSomething(String input) { // Shockingly, this does something }
Timber • Smarter alternative to Log Timber.i("Something bad happened", exception);
gradle-versions-plugin • Keep your dependencies up-to-date • https://github.com/ben-manes/gradle-versions- plugin
Fun Libraries • Calligraphy - Automatic fonts! • Gradle retrolambda
- Lambdas in Android! • Butterknife - Annotated views! • RoundedImageView - Easy rounded corners! • Mockito - Mocked objects for testing! • Victor - SVGs as resources!
Finding Libraries
Collections • Explore: https://android-arsenal.com/ • Demo: https://play.google.com/store/apps/details? id=com.desarrollodroide.repos
Gradle, Please • Shortcut for getting exact dependency string •
http://gradleplease.appspot.com
Google • A search engine: http://google.com • Type in what
you want • Take a gamble with “I’m feeling lucky”
Thank You! • http://blog.danlew.net • @danlew42 • +DanielLew