Save 37% off PRO during our Black Friday Sale! »

Android Dependencies You Can Depend On

Android Dependencies You Can Depend On

D225ebf0faa666ac7655cc7e4689283c?s=128

Daniel Lew
PRO

March 21, 2015
Tweet

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