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

Android Dependencies You Can Depend On

Android Dependencies You Can Depend On

Daniel Lew

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

    View Slide

  2. Why Libraries?
    • Stand on the shoulders of giants
    • Hit the ground running
    • Easier than ever to use

    View Slide

  3. Adding Libraries
    repositories {

    jcenter()

    }


    dependencies {

    compile 'com.squareup.retrofit:retrofit:1.9.0'

    }

    View Slide

  4. Which Libraries?

    View Slide

  5. My Basic Stack
    • Retrofit
    • GSON
    • Picasso
    • OkHttp
    • Dagger
    • RxJava

    View Slide

  6. Retrofit
    • …Because a lot of people use REST
    • …Because REST is easy to understand

    View Slide

  7. Example API
    http://company.com/api/public/cards?id=someId

    View Slide

  8. Define an Interface
    http://company.com/api/public/cards?id=someId
    public interface MyService {


    @GET("/api/{visibility}/cards")

    List getCards(@Path("visibility") String visibility, 

    @Query("id") String id);


    }

    View Slide

  9. Create a RestAdapter
    RestAdapter restAdapter = new RestAdapter.Builder()

    .setEndpoint("http://company.com")

    .build();


    MyService service = restAdapter.create(MyService.class);

    View Slide

  10. Use the service
    List cards = service.getCards("public", "someId");

    View Slide

  11. GSON
    • …Because many REST APIs use JSON

    View Slide

  12. JSON vs. Object
    • JSON
    {

    "id": "someId",

    "data": "Some data"

    }
    • Class
    public class Card {


    private String id;


    private String data;


    }

    View Slide

  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();

    }

    View Slide

  14. With GSON
    String jsonStr = /* ...whatever you get from Retrofit... */;

    Gson gson = new Gson();

    Card card = gson.fromJson(jsonStr, Card.class);

    View Slide

  15. Customizable
    • Can handle differently named fields:
    public class Card {


    @SerializedName("theId")

    private String id;


    @SerializedName("theData")

    private String data;


    }
    • Custom deserializers (type adapters)

    View Slide

  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);

    View Slide

  17. Picasso
    • Easy image loading
    Picasso.with(this)

    .load("http://path.to/image.png")

    .into(someImageView);

    View Slide

  18. Picasso Options
    Picasso.with(this)

    .load("http://path.to/image.png")

    .placeholder(R.drawable.placeholder)

    .centerCrop()

    .into(someImageView);

    View Slide

  19. OkHttp
    • Consistent HTTP implementation
    • Better HTTP implementation
    • Easier HTTP implementation
    • Drives other libraries

    View Slide

  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();

    View Slide

  21. OkHttp + Picasso
    Picasso picasso = new Picasso.Builder()

    .downloader(new OkHttpDownloader())
    .build();

    picasso.load("http://path.to/image.png")

    .into(someImageView);

    View Slide

  22. Dagger
    • Dependency injection!
    • …What does that really mean?
    • …Why do you want it?

    View Slide

  23. Components
    • RestAdapter
    • Gson
    • Picasso
    • OkHttp
    • …All intertwined

    View Slide

  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();

    View Slide

  25. Solving the Bad
    • Problem: Need to cache components
    • Solution: static singletons!

    View Slide

  26. It is now impossible to
    test most of your code

    View Slide

  27. Solution
    Dependency injection!

    View Slide

  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;

    }

    }

    View Slide

  29. Unfortunately…
    • Passing around dependencies is a PITA!
    • Dagger: Handles busywork for you

    View Slide

  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);

    }

    }

    View Slide

  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);

    }


    }

    View Slide

  32. RxJava
    • Reactive framework
    • Less coding
    • Easy error handling
    • Easy concurrency
    • Just plain fun
    • …But not easy to understand at first

    View Slide

  33. Observer Pattern
    Observable.just("1", "2", "3")

    .subscribe(new Action1() {

    @Override public void call(String s) {

    System.out.println(s);

    }

    });

    View Slide

  34. Operators
    Observable.just("1", "2", "3")

    .map(new Func1() {

    @Override public String call(String s) {

    return "item: " + s;

    }

    })

    .subscribe(new Action1() {

    @Override public void call(String s) {

    System.out.println(s);

    }

    });

    View Slide

  35. Schedulers
    Observable.just("1", "2", "3")

    .map(new Func1() {

    @Override public String call(String s) {

    return "item: " + s;

    }

    })

    .subscribeOn(Schedulers.io())

    .observeOn(AndroidSchedulers.mainThread())

    .subscribe(new Action1() {

    @Override

    public void call(String s) {

    System.out.println(s);

    }

    });

    View Slide

  36. Error Handling
    Observable.just("1", "2", "3")

    .map(new Func1() {

    @Override

    public String call(String s) {

    return "item: " + s;

    }

    })

    .subscribeOn(Schedulers.io())

    .observeOn(AndroidSchedulers.mainThread())

    .subscribe(

    new Action1() {

    @Override public void call(String s) {

    System.out.println(s);

    }

    },

    new Action1() {

    @Override public void call(Throwable throwable) {

    System.out.println("Something went wrong!");

    }

    });

    View Slide

  37. u2020
    • Great sample for (most) of basic stack
    • https://github.com/JakeWharton/u2020/

    View Slide

  38. Alternatives
    • Everything has alternatives
    • Impact, not implementation
    • Weigh pros/cons

    View Slide

  39. Development Libraries

    View Slide

  40. Stetho
    • Debug bridge on Chrome

    View Slide

  41. Stetho
    • Debug bridge on Chrome

    View Slide

  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

    }


    View Slide

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

    View Slide

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

    View Slide

  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!

    View Slide

  46. Finding Libraries

    View Slide

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

    View Slide

  48. Gradle, Please
    • Shortcut for getting exact dependency string
    • http://gradleplease.appspot.com

    View Slide

  49. Google
    • A search engine: http://google.com
    • Type in what you want
    • Take a gamble with “I’m feeling lucky”

    View Slide

  50. Thank You!
    • http://blog.danlew.net
    • @danlew42
    • +DanielLew

    View Slide