Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Things I learned about native Android app devel...

S Gaw
April 05, 2016

Things I learned about native Android app development the extra hard way

Interested in becoming a native Android application developer? I will cover tips I learned from transitioning from backend Java development. This includes an overview of the fragmented Android ecosystem as well as the consequential challenges for Android development to handle the following:

• Multiple device sizes, resolutions
• Screen orientations
• Localization (text, component alignment)

These considerations will be framed in terms of the Android build system workflow (*).

(*) Don’t worry, I will not cover all of the steps.

S Gaw

April 05, 2016
Tweet

More Decks by S Gaw

Other Decks in Technology

Transcript

  1. I KNOW JAVA, ANDROID DEVELOPERS CODE IN JAVA (*), RIGHT?

    IT ALL SEEMED EASY AT FIRST (*) A smaller fraction might do it in Kotlin, Android Swift
  2. MY OLD BACKEND WORLD: JAVA SOURCE CODE TO RUNNING APPLICATIONS

    SIMPLE JAVA APPLICATIONS ▸ To Java byte code (class files) ▸ To java runtime Image: http://www.javaguicodexample.com/javainstalltestusejdk.html
  3. MY OLD BACKEND WORLD: JAVA SOURCE CODE TO RUNNING APPLICATIONS

    SIMPLE JAVA APPLICATIONS ▸ To Java byte code (class files) ▸ To java runtime
  4. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    ANDROID APPS ▸ To Java byte code ▸ To Java runtime ▸ … ▸ To Android APKs ▸ To Android devices ▸ To Android runtime Images: http://developer.android.com/about/versions/lollipop.html http://crackberry.com/android
  5. UMBERTO ECO …ARGUED THAT THE APPLE MAC WAS A CATHOLIC

    MACHINE, IN CONTRAST TO THE PC, WHICH, HE ARGUED, WAS CLEARLY A PROTESTANT DEVICE. HOW SO? JOHN NAUGHTON http://www.theguardian.com/commentisfree/2015/oct/18/were-all-casualties-holy-war-android-security-apple-john-naughton
  6. THE MAC FREED ITS USERS/BELIEVERS FROM THE NEED TO MAKE

    DECISIONS. ALL THEY HAD TO DO TO FIND SALVATION WAS TO FOLLOW THE APPLE WAY. IN CONTRAST, ECO POINTED OUT, THE POOR WRETCHES WHO USED A PC HAD, LIKE THE CALVINISTS OF YORE – TO MAKE THEIR OWN SALVATION. FOR THEM, THERE WAS NO ONE TRUE WAY.
  7. TODAY’S CATHOLICS HAVE IPHONES RUNNING THE APPLE IOS OPERATING SYSTEM…

    WHILE THE CALVINISTS HAVE DEVICES MADE BY A HOST OF MANUFACTURERS AND POWERED BY VARIOUS FLAVOURS OF THE ANDROID OPERATING SYSTEM.
  8. Phone Platform 2015 Q2 Market Share Android 82,8 % iOS

    13,9 % Windows 2,6 % Other 0,7 % *Source: http://www.idc.com/prodserv/smartphone-os-market-share.jsp
  9. Phone Manufacturer 2015 Q2 Market Share Samsung 21.4 % Apple

    13,9 % Huawei 8.7 % Xiaomi 5,6 % Lenovo/Motorola 4,9 % Other 45,7 % *Source: http://www.idc.com/prodserv/smartphone-os-market-share.jsp
  10. Top Android Phone Manufacturers Market Share Samsung 51,6 % LG

    5,9 % Huawei 4,3 % Motorola 3,9 % Lenovo 3,9 % HTC 2,5 % *Source: http://www.appbrain.com/stats/top-manufacturers
  11. Top Android Phone Model Market Share Samsung Galaxy S3 3,4

    % Samsung Galaxy Grand Prime 3,0 % Samsung Galaxy S5 2,8 % Samsung Galaxy S4 2,7 % Samsung Galaxy Note3 2,3 % Motorola Moto G 2,1 % *Source: http://www.appbrain.com/stats/top-android-phones
  12. TODAY’S CATHOLICS HAVE IPHONES RUNNING THE APPLE IOS OPERATING SYSTEM…

    WHILE THE CALVINISTS HAVE DEVICES MADE BY A HOST OF MANUFACTURERS AND POWERED BY VARIOUS FLAVOURS OF THE ANDROID OPERATING SYSTEM.
  13. WHILE THE CALVINISTS HAVE DEVICES MADE BY A HOST OF

    MANUFACTURERS AND POWERED BY VARIOUS FLAVOURS OF THE ANDROID OPERATING SYSTEM.
  14. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    ANDROID APPS ▸ To Java byte code ▸ To Java runtime ▸ … ▸ To Android APKs ▸ To Android devices ▸ To Android runtime Images: http://developer.android.com/about/versions/lollipop.html http://crackberry.com/android
  15. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    (2) ANDROID APPS ▸ To Java byte code ▸ … ▸ To Android devices ▸ To Android runtime
  16. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    (2) ANDROID APPS ▸ To Java byte code ▸ … ▸ To dex byte code ▸ … ▸ To Android devices ▸ To Android runtime
  17. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    (2) ANDROID APPS ▸ To Java byte code ▸ … ▸ To dex byte code ▸ To Android APKs ▸ … ▸ To Android devices ▸ To Android runtime
  18. BUILD.GRADLE (MY APPLICATION) buildscript { repositories { jcenter() } dependencies

    { classpath 'com.android.tools.build:gradle:2.0.0-rc1' } } https://bintray.com/bintray/jcenter Image: http://androidxiphone.com/wp-content/uploads/2015/02/Best-Android-Tools-Apps-2015.png
  19. BUILD.GRADLE (APP) apply plugin: 'com.android.application'
 
 android {
 …
 buildToolsVersion

    "23.0.0 rc3"
 
 defaultConfig {
 applicationId "com.playground.sgaw.sample.myapplication"
 … }
 buildTypes {
 … }
 }
 
 dependencies {
 …
 }

  20. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    (2) ANDROID APPS ▸ To Java byte code ▸ … ▸ To dex byte code ▸ To Android APKs ▸ … ▸ To Android devices ▸ To Android runtime
  21. bash-3.2$ ./gradlew assembleDebug Download https://jcenter.bintray.com/com/android/tools/ build/gradle/2.0.0-rc1/gradle-2.0.0-rc1.pom … Incremental java compilation

    is an incubating feature. :app:preBuild UP-TO-DATE … :app:compileDebugSources :app:prePackageMarkerForDebug :app:transformClassesWithDexForDebug … :app:packageDebug :app:zipalignDebug :app:assembleDebug BUILD SUCCESSFUL Total time: 29.956 secs
  22. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    (2) ANDROID APPS ▸ To Java byte code ▸ … ▸ To dex byte code ▸ To Android APKs ▸ To Android devices ▸ To Android runtime
  23. FAVOURING PLAIN OLD JAVA OBJECTS (POJO) UNIT TESTING ▸ Android’s

    runtime byte code != Java byte code ▸ Java unit tests != Android unit tests (*) ▸ (*) Java unit tests == Android unit tests iff compilation stops at Java byte code
  24. JAVA SOURCE CODE TO JAVA UNIT TESTS ANDROID APPS ▸

    To Java byte code ▸ (Run Java unit tests) ▸ … ▸ To dex byte code ▸ To Android APKs ▸ To Android devices ▸ To Android runtime
  25. bash-3.2$ ./gradlew --daemon test Incremental java compilation is an incubating

    feature. … :app:compileDebugJavaWithJavac UP-TO-DATE :app:preDebugUnitTestBuild UP-TO-DATE :app:prepareDebugUnitTestDependencies :app:compileDebugUnitTestJavaWithJavac :app:processDebugJavaRes UP-TO-DATE :app:processDebugUnitTestJavaRes UP-TO-DATE :app:compileDebugUnitTestSources :app:mockableAndroidJar :app:assembleDebugUnitTest :app:testDebugUnitTest … :app:test BUILD SUCCESSFUL Total time: 10.806 secs bash-3.2$
  26. <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:paddingBottom="@dimen/activity_vertical_margin"
 android:paddingLeft="@dimen/activity_horizontal_margin"


    android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 tools:context="com.playground.sgaw.sample.myapplication.MainActivity">
 
 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Hello World!"/>
 </RelativeLayout>

  27. <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout
 xmlns:android="http://schemas.android.com xmlns:tools="http://schemas.android.com/t android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:paddingBottom="@dimen/activity_ve android:paddingLeft="@dimen/activity_hori

    android:paddingRight="@dimen/activity_hor android:paddingTop="@dimen/activity_verti tools:context="com.playground.sgaw.sample 
 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Hello World!"/>
 </RelativeLayout>

  28. <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:background="@android:color/holo_red_dark"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:paddingBottom="@dimen/activity_vertical_margin"


    android:paddingLeft="@dimen/activity_horizontal_margin"
 android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 tools:context="com.playground.sgaw.sample.myapplication.MainActivity">
 
 <TextView
 android:background="@android:color/holo_green_dark"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Hello World!"/>
 </RelativeLayout>

  29. <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:background="@android:color/holo_red_dark"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:paddingBottom="@dimen/activity_vertical_margin"


    android:paddingLeft="@dimen/activity_horizontal_margin"
 android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 tools:context="com.playground.sgaw.sample.myapplication.MainActivity">
 
 <TextView
 android:background="@android:color/holo_green_dark"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Hello World!"/>
 </RelativeLayout>

  30. <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 tools:background="@android:color/holo_red_dark"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:paddingBottom="@dimen/activity_vertical_margin"


    android:paddingLeft="@dimen/activity_horizontal_margin"
 android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 tools:context="com.playground.sgaw.sample.myapplication.MainActivity">
 
 <TextView
 tools:background="@android:color/holo_green_dark"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Hello World!"/>
 </RelativeLayout>
 https://www.youtube.com/watch?v=AeoeD7K8vKI https://speakerdeck.com/rock3r/tools-of-the-trade-droidcon-nyc-2015
  31. MyProject/ src/ MyActivity.java res/ drawable/ graphic.png layout/ main.xml info.xml mipmap/

    icon.png values/ strings.xml http://developer.android.com/guide/topics/resources/providing-resources.html ALTERNATIVE RESOURCES: SCREEN ORIENTATION
  32. MyProject/ src/ MyActivity.java res/ drawable/ graphic.png layout/ main.xml info.xml mipmap/

    icon.png values/ strings.xml ALTERNATIVE RESOURCES: SCREEN ORIENTATION MyProject/ … layout/ main.xml info.xml layout-land/ main.xml …
  33. WHILE THE CALVINISTS HAVE DEVICES MADE BY A HOST OF

    MANUFACTURERS AND POWERED BY VARIOUS FLAVOURS OF THE ANDROID OPERATING SYSTEM.
  34. ALTERNATIVE RESOURCES: SCREEN SIZES MyProject/ src/ MyActivity.java res/ drawable/ graphic.png

    layout/ main.xml info.xml mipmap/ icon.png values/ strings.xml http://developer.android.com/guide/topics/resources/providing-resources.html small normal large xlarge sw320dp sw600dp sw720dp Screen size Minimum screen width
  35. ALTERNATIVE RESOURCES: SCREEN SIZES MyProject/ src/ MyActivity.java res/ drawable/ graphic.png

    layout/ main.xml info.xml mipmap/ icon.png values/ strings.xml http://developer.android.com/guide/topics/resources/providing-resources.html sw320dp sw600dp sw720dp Minimum screen width MyProject/ src/ MyActivity.java res/ drawable/ graphic.png layout/ main.xml info.xml mipmap/ icon.png values/ strings.xml sw320dp sw600dp sw720dp
  36. ALTERNATIVE RESOURCES: SCREEN SIZES MyProject/ src/ MyActivity.java res/ drawable/ graphic.png

    layout/ main.xml info.xml mipmap/ icon.png values/ strings.xml http://developer.android.com/guide/topics/resources/providing-resources.html sw320dp sw600dp sw720dp MyProject/ src/ MyActivity.java res/ drawable/ graphic.png layout/ main.xml info.xml mipmap/ icon.png values/ strings.xml sw320dp sw600dp sw720dp MyProject/ … layout/ main.xml … layout-sw600dp/ main.xml …
  37. ALTERNATIVE RESOURCES: SCREEN DENSITY MyProject/ src/ MyActivity.java res/ drawable/ graphic.png

    layout/ main.xml info.xml mipmap/ icon.png values/ strings.xml http://developer.android.com/guide/topics/resources/providing-resources.html ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi nodpi tvdpi
  38. ALTERNATIVE RESOURCES MyProject/ src/ MyActivity.java res/ drawable/ graphic.png layout/ main.xml

    info.xml mipmap/ icon.png values/ strings.xml http://developer.android.com/guide/topics/resources/providing-resources.html ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi nodpi tvdpi MyProject/ … drawable-mdpi/ graphic.png drawable-hdpi/ graphic.png drawable-xdpi/ graphic.png drawable-xxdpi/ graphic.png … ALTERNATIVE RESOURCES: SCREEN DENSITY
  39. http://cyrilmottier.com/2014/08/26/putting-your-apks-on-diet/ (Caveat: Feb 2015) Ideally use vector drawables in support

    library 23.2 http://android-developers.blogspot.fr/ 2016/02/android-support- library-232.html
  40. ALTERNATIVE RESOURCES: LOCALIZATION MyProject/ src/ MyActivity.java res/ drawable/ graphic.png layout/

    main.xml info.xml mipmap/ icon.png values/ strings.xml es fr de it
  41. ALTERNATIVE RESOURCES: LOCALIZATION MyProject/ src/ MyActivity.java res/ drawable/ graphic.png layout/

    main.xml info.xml mipmap/ icon.png values/ strings.xml es fr de it MyProject/ … values/ strings.xml values-es/ strings.xml values-fr/ strings.xml values-de/ strings.xml values-it/ strings.xml …
  42. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    (2) ANDROID APPS ▸ To Java byte code ▸ … ▸ To dex byte code ▸ To Android APKs ▸ To Android devices ▸ To Android runtime
  43. FAVOURING PLAIN OLD JAVA OBJECTS (POJO) UNIT TESTING ▸ Android’s

    runtime byte code != Java byte code ▸ Java unit tests != Android unit tests (*) ▸ (*) Java unit tests == Android unit tests iff compilation stops at Java byte code
  44. bash-3.2$ ./gradlew --daemon --continuous test Continuous build is an incubating

    feature. Incremental java compilation is an incubating feature. … :app:compileDebugJavaWithJavac UP-TO-DATE :app:preDebugUnitTestBuild UP-TO-DATE :app:prepareDebugUnitTestDependencies :app:compileDebugUnitTestJavaWithJavac UP-TO-DATE :app:processDebugJavaRes UP-TO-DATE :app:processDebugUnitTestJavaRes UP-TO-DATE :app:compileDebugUnitTestSources UP-TO-DATE :app:mockableAndroidJar UP-TO-DATE :app:assembleDebugUnitTest UP-TO-DATE :app:testDebugUnitTest UP-TO-DATE
  45. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    (2) ANDROID APPS ▸ To Java byte code ▸ … ▸ To dex byte code ▸ To Android APKs ▸ To Android devices ▸ To Android runtime
  46. THE MOBILE WORLD: JAVA SOURCE CODE TO RUNNING ANDROID APPS

    (3) ANDROID APPS ▸ (Plus android.jar) ▸ To Java byte code ▸ … ▸ To dex byte code ▸ To Android APKs ▸ To Android devices ▸ To Android runtime
  47. THE ANDROID.JAR FILE THAT IS USED TO RUN UNIT TESTS

    DOES NOT CONTAIN ANY ACTUAL CODE - THAT IS PROVIDED BY THE ANDROID SYSTEM IMAGE ON REAL DEVICES. INSTEAD, ALL METHODS THROW EXCEPTIONS (BY DEFAULT). http://tools.android.com/tech-docs/unit-testing- support UNIT TESTS
  48. WHY IS THIS STUBBED OUT?! ANDROID.JAR’S SCOPE IS LARGER THAN

    YOU’D THINK ▸ Android OS (files, network, database, …) ▸ Android data containers (Context, Bundle, Intent, SharedPreferences) ▸ Memory savers like optimized data structures (SparseArray, …) ▸ Log statements ▸ JSON parsing
  49. WHY IS THIS STUBBED OUT?! ANDROID.JAR’S SCOPE IS LARGER THAN

    YOU’D THINK ▸ Android OS (files, network, database, …) ▸ Android data containers (Context, Bundle, Intent, SharedPreferences) ▸ Memory savers like optimized data structures (SparseArray, …) ▸ Log statements ▸ JSON parsing “Use Android- Appropriate Data Structures” https://medium.com/google-developers/developing-for-android-v-f6b8038b42f5#.g96l5ayh1
  50. OPTIONS FOR USING ANDROID.JAR ▸ Ignore exceptions via build.gradle configuration

    ▸ Mock behavior ▸ Use instrumentation unit tests ▸ Android instrumented unit tests ▸ Robolectric unit tests ▸ Espresso tests http://fragmentedpodcast.com/episodes/1/
  51. OPTIONS FOR USING ANDROID.JAR ▸ Ignore exceptions via build.gradle configuration

    ▸ Mock behavior ▸ Use instrumentation unit tests ▸ Android instrumented unit tests ▸ Robolectric unit tests ▸ Espresso tests
  52. apply plugin: 'com.android.application'
 
 android {
 …
 buildToolsVersion "23.0.0 rc3"


    
 defaultConfig {
 applicationId "com.playground.sgaw.sample.myapplication"
 … }
 buildTypes {
 … } testOptions {
 unitTests.returnDefaultValues = true
 } 
 }
 
 http://tools.android.com/tech-docs/unit-testing-support
  53. OPTIONS FOR USING ANDROID.JAR ▸ Ignore exceptions via build.gradle configuration

    ▸ Mock behavior ▸ Use instrumentation unit tests ▸ Android instrumented unit tests ▸ Robolectric unit tests ▸ Espresso tests
  54. OPTIONS FOR USING ANDROID.JAR ▸ Ignore exceptions via build.gradle configuration

    ▸ Mock behavior ▸ Use instrumentation unit tests ▸ Android instrumented unit tests ▸ Robolectric unit tests ▸ Espresso tests http://fragmentedpodcast.com/episodes/1/
  55. WHY IS THIS STUBBED OUT?! ANDROID.JAR’S SCOPE IS LARGER THAN

    YOU’D THINK ▸ Android OS (files, network, database, …) ▸ Android data containers (Context, Bundle, Intent, SharedPreferences) ▸ Memory savers like optimized data structures (SparseArray, …) ▸ Log statements ▸ JSON parsing “Use Android- Appropriate Data Structures”
  56. COUNTER-INTUITIVELY, THIS IS NOT INCLUDED… ANDROID.JAR’S SCOPE IS SMALLER THAN

    YOU’D THINK ▸ play services (app invites, analytics, Maps API, Wallet) ▸ support library for backward compatibility
  57. ANDROID’S PROLIFERATION IS THE STUFF OF NIGHTMARES ANDROID.JAR’S SCOPE IS

    SMALLER THAN YOU’D THINK ▸ play services (app invites, analytics, Maps API, Wallet) because Google cannot force OS updates but want a consistent functionality ▸ support library for backward compatibility because Google cannot force OS updates when they don’t manufacture the phones and when the OS is open source
  58. COUNTER-INTUITIVELY, THIS IS NOT INCLUDED… ANDROID.JAR’S SCOPE IS SMALLER THAN

    YOU’D THINK ▸ play services (app invites, analytics, Maps API, Wallet) ▸ support library for backward compatibility “Use Android- Appropriate Data Structures”
  59. COUNTER-INTUITIVELY, THIS IS NOT INCLUDED… ANDROID.JAR’S SCOPE IS SMALLER THAN

    YOU’D THINK ▸ play services (app invites, analytics, Maps API, Wallet) ▸ support library for backward compatibility “Use Android- Appropriate Data Structures”
  60. COUNTER-INTUITIVELY, THIS IS NOT INCLUDED… ANDROID.JAR’S SCOPE IS SMALLER THAN

    YOU’D THINK ▸ play services (app invites, analytics, Maps API, Wallet) ▸ support library for backward compatibility “Use Android- Appropriate Data Structures”
  61. ANDROID’S PROLIFERATION IS THE STUFF OF NIGHTMARES ANDROID.JAR’S SCOPE IS

    SMALLER THAN YOU’D THINK ▸ support library for backward compatibility because Google cannot force OS updates when they don’t manufacture the phones and when the OS is open source ▸ play services (app invites, analytics, Maps API, Wallet) because Google cannot force OS updates but want a consistent functionality
  62. FOR ANDROID WORSHIPPERS… THEIR FATE LARGELY DEPENDS ON HOW CONSCIENTIOUS

    THE MANUFACTURER OF THEIR DEVICE IS ABOUT KEEPING THEM UP TO DATE…
  63. AND WHEN THE CATHOLICS PUT THEIR DEVICES ON TO CHARGE

    OVERNIGHT THEY WAKE UP IN THE MORNING TO FIND THAT APPLE HAS DOWNLOADED YET ANOTHER UPDATE.
  64. REFERENCES ▸ Documentation: http://developer.android.com/develop/index.html ▸ API Reference: https://developer.android.com/reference/packages.html ▸ Android

    developers: http://android-developers.blogspot.fr/ ▸ Android Developers (YouTube) : https://www.youtube.com/channel/UCVHFbqXqoYvEWM1Ddxl0QDg ▸ Fragmented Podcast: http://fragmentedpodcast.com/ ▸ Android Weekly newsletter: http://androidweekly.net/ ▸ The Cheese Sheet http://inthecheesefactory.com/aca/The Android Cheese Sheet rev 4.pdf ▸ Jake Wharton, https://twitter.com/JakeWharton ▸ Cyril Mottier, https://twitter.com/cyrilmottier
  65. COMMON LIBRARIES ▸ Glide, https://github.com/bumptech/glide ▸ Square GitHub, http://square.github.io/ ▸

    Retrofit, http://square.github.io/retrofit/ ▸ OkHttp, http://square.github.io/okhttp/