$30 off During Our Annual Pro Sale. View Details »

Android Dependencies You Can Depend On

Android Dependencies You Can Depend On

Daniel Lew
PRO

March 21, 2015
Tweet

More Decks by Daniel Lew

Other Decks in Programming

Transcript

  1. Android Dependencies You Can Depend On Dan Lew 3/21/2015

  2. Why Libraries? • Stand on the shoulders of giants •

    Hit the ground running • Easier than ever to use
  3. Adding Libraries repositories {
 jcenter()
 }
 
 dependencies {
 compile

    'com.squareup.retrofit:retrofit:1.9.0'
 }
  4. Which Libraries?

  5. My Basic Stack • Retrofit • GSON • Picasso •

    OkHttp • Dagger • RxJava
  6. Retrofit • …Because a lot of people use REST •

    …Because REST is easy to understand
  7. Example API http://company.com/api/public/cards?id=someId

  8. 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);
 
 }
  9. Create a RestAdapter RestAdapter restAdapter = new RestAdapter.Builder()
 .setEndpoint("http://company.com")
 .build();


    
 MyService service = restAdapter.create(MyService.class);
  10. Use the service List<Card> cards = service.getCards("public", "someId");

  11. GSON • …Because many REST APIs use JSON

  12. JSON vs. Object • JSON {
 "id": "someId",
 "data": "Some

    data"
 } • Class public class Card {
 
 private String id;
 
 private String data;
 
 }
  13. 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();
 }
  14. With GSON String jsonStr = /* ...whatever you get from

    Retrofit... */;
 Gson gson = new Gson();
 Card card = gson.fromJson(jsonStr, Card.class);
  15. Customizable • Can handle differently named fields: public class Card

    {
 
 @SerializedName("theId")
 private String id;
 
 @SerializedName("theData")
 private String data;
 
 } • Custom deserializers (type adapters)
  16. Retrofit with GSON RestAdapter restAdapter = new RestAdapter.Builder()
 .setEndpoint("http://company.com")
 .setConverter(new

    GsonConverter(new Gson()))
 .build();
 
 MyService service = restAdapter.create(MyService.class);
  17. Picasso • Easy image loading Picasso.with(this)
 .load("http://path.to/image.png")
 .into(someImageView);

  18. Picasso Options Picasso.with(this)
 .load("http://path.to/image.png")
 .placeholder(R.drawable.placeholder)
 .centerCrop()
 .into(someImageView);

  19. OkHttp • Consistent HTTP implementation • Better HTTP implementation •

    Easier HTTP implementation • Drives other libraries
  20. OkHttp + Retrofit • Add client to RestAdapter RestAdapter restAdapter

    = new RestAdapter.Builder()
 .setEndpoint("http://company.com")
 .setConverter(new GsonConverter(new Gson()))
 .setClient(new OkClient())
 .build();
  21. OkHttp + Picasso Picasso picasso = new Picasso.Builder()
 .downloader(new OkHttpDownloader())

    .build(); 
 picasso.load("http://path.to/image.png")
 .into(someImageView);
  22. Dagger • Dependency injection! • …What does that really mean?

    • …Why do you want it?
  23. Components • RestAdapter • Gson • Picasso • OkHttp •

    …All intertwined
  24. 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();
  25. Solving the Bad • Problem: Need to cache components •

    Solution: static singletons!
  26. It is now impossible to test most of your code

  27. Solution Dependency injection!

  28. 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;
 }
 }
  29. Unfortunately… • Passing around dependencies is a PITA! • Dagger:

    Handles busywork for you
  30. 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);
 }
 }
  31. 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);
 }
 
 }
  32. RxJava • Reactive framework • Less coding • Easy error

    handling • Easy concurrency • Just plain fun • …But not easy to understand at first
  33. Observer Pattern Observable.just("1", "2", "3")
 .subscribe(new Action1<String>() {
 @Override public

    void call(String s) {
 System.out.println(s);
 }
 });
  34. 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);
 }
 });
  35. 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);
 }
 });
  36. 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!");
 }
 });
  37. u2020 • Great sample for (most) of basic stack •

    https://github.com/JakeWharton/u2020/
  38. Alternatives • Everything has alternatives • Impact, not implementation •

    Weigh pros/cons
  39. Development Libraries

  40. Stetho • Debug bridge on Chrome

  41. Stetho • Debug bridge on Chrome

  42. 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
 }

  43. Timber • Smarter alternative to Log Timber.i("Something bad happened", exception);

  44. gradle-versions-plugin • Keep your dependencies up-to-date • https://github.com/ben-manes/gradle-versions- plugin

  45. 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!
  46. Finding Libraries

  47. Collections • Explore: https://android-arsenal.com/ • Demo: https://play.google.com/store/apps/details? id=com.desarrollodroide.repos

  48. Gradle, Please • Shortcut for getting exact dependency string •

    http://gradleplease.appspot.com
  49. Google • A search engine: http://google.com • Type in what

    you want • Take a gamble with “I’m feeling lucky”
  50. Thank You! • http://blog.danlew.net • @danlew42 • +DanielLew