Tools of the Trade (Droidcon NYC 2015)

Tools of the Trade (Droidcon NYC 2015)

This talk will tour one of the most understated resources in the Android developer arsenal: the support tools.

Learn how to enrich your methods and classes using annotations, so that Lint and Android Studio will be able to spot errors for you. Or use IntelliJ annotations to define contracts, and let the IDE warn you of potential issues before you even run your code once. Take advantage of the tools namespace to bend even the most cryptic XML resource to your will.
----
Since this deck is quite heavy on the animations side, I've exported a video version of it as well, that you can find here: http://youtu.be/z9zyQwyO8l0
----
The talk video is now available here: https://www.youtube.com/watch?v=AeoeD7K8vKI

4580c218737149bf44d012a110612010?s=128

Sebastiano Poggi

August 28, 2015
Tweet

Transcript

  1. TOOLS Sebastiano Poggi Novoda, Android GDE TRADE OF THE #toolsOfTrade

  2. None
  3. None
  4. None
  5. None
  6. 1.3 Android Studio

  7. “How can this be a NPE?” “I wish things were

    strongly typed, all resource IDs look like any other integer!”
  8. “How can this be a NPE?” “I wish things were

    strongly typed, all resource IDs look like any other integer!” “Why isn’t this text R.color.red? It’s showing as black!”
  9. “How can this be a NPE?” “I wish things were

    strongly typed, all resource IDs look like any other integer!” “Why isn’t this text R.color.red? It’s showing as black!” “I love Eclipse!”
  10. “How can this be a NPE?” “I wish things were

    strongly typed, all resource IDs look like any other integer!” “Why isn’t this text R.color.red? It’s showing as black!” “I love Eclipse!” “What? I thought this was on the
  11. “How can this be a NPE?” “I wish things were

    strongly typed, all resource IDs look like any other integer!” “Why isn’t this text R.color.red? It’s showing as black!” “I love Eclipse!” “What? I thought this was on the UI thread, but it’s crashing”
  12. Great news!*

  13. Great news!*

  14. Great news!* Annotations and XML attributes will save the day

  15. SURPRISE QUESTION Lint

  16. Lint Born in 1979 for C

  17. Lint Born in 1979 for C Performs static code analysis

  18. Lint Born in 1979 for C Performs static code analysis

    Should be part of your CI builds
  19. Lint Born in 1979 for C Performs static code analysis

    Should be part of your CI builds
  20. tools xmlns:

  21. tools xmlns: namespac

  22. tools xmlns: namespace Built into the SDK/Android Studio

  23. tools namespace Built into the SDK/Android Studio Safe to commit

    under VCS
  24. tools namespace Built into the SDK/Android Studio Safe to commit

    under VCS (Usually)
  25. tools namespace Built into the SDK/Android Studio Safe to commit

    under VCS (Usually)
  26. <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" ... Design-time overrides Override any android attribute

    /> tools:text="Hello world!"
  27. Design-time overrides Override any android attribute /> tools:text="Hello world!" <TextView


    android:layout_width="wrap_content"
 android:layout_height="wrap_content" ...
  28. Tools attributes Lint attributes

  29. Tools attributes Lint attributes Design attributes

  30. Tools attributes Lint attributes Design attributes

  31. Tools attributes Lint attributes Design attributes

  32. <application
 android:name=".MyApplication"
 android:label="Babou" ... /> Should explicitly set allowBackup… Lint

    attribute: ignore Similar to @SuppressWarnings
  33. /> <application
 android:name=".MyApplication"
 android:label="Babou" ... Should explicitly set allowBackup… Lint

    attribute: ignore Similar to @SuppressWarnings tools:ignore="AllowBackup"
  34. <application
 android:name=".MyApplication"
 android:label="Babou" ... Lint attribute: ignore Similar to @SuppressWarnings

    /> tools:ignore="AllowBackup" tools:ignore="AllowBackup"
  35. <style name="Widget.FAB"> ... Lint attribute: targetApi Equivalent to @TargetApi />

    <item android:elevation="8dp" </style> tools:targetApi="HONEYCOMB" android:elevation requires API level 21(current min is 19)
  36. <style name="Widget.FAB"> ... Lint attribute: targetApi Equivalent to @TargetApi />

    <item android:elevation="8dp" </style> tools:targetApi="LOLLIPOP" /> android:elevation requires API level 21(current min is 19)
  37. <style name="Widget.FAB"> ... Lint attribute: targetApi Equivalent to @TargetApi <item

    android:elevation="8dp" </style> tools:targetApi="LOLLIPOP" />
  38. <resources Lint attribute: locale Helps spell checking <string name="typo">Helo, I

    am a typo.</string> </resources> > tools:locale="en">
  39. <resources Lint attribute: locale Helps spell checking <string name="typo">Helo, I

    am a typo.</string> </resources> tools:locale="en">
  40. Tools attributes Lint attributes Design attributes

  41. <merge xmlns:android="..." Design attribute: context Helps AS tying a layout

    to an Activity android:layout_width="match_parent"
 android:layout_height="match_parent" ... </merge> > tools:context=".map.MapActivity"
  42. <merge xmlns:android="..." Design attribute: context Helps AS tying a layout

    to an Activity android:layout_width="match_parent"
 android:layout_height="match_parent" ... </merge> > tools:context=".map.MapActivity"
  43. <merge xmlns:android="..." Design attribute: context Helps AS tying a layout

    to an Activity android:layout_width="match_parent"
 android:layout_height="match_parent" tools:context=".map.MapActivity" ... </merge> >
  44. <merge xmlns:android="..." Design attribute: showIn Shows a merge in its

    parent layout’s include android:layout_width="match_parent"
 android:layout_height="match_parent" ... </merge> > tools:showIn="@layout/activity_main"
  45. <merge xmlns:android="..." android:layout_width="match_parent"
 android:layout_height="match_parent" tools:showIn="@layout/activity_main" ... </merge> > Design attribute:

    showIn Shows a merge in its parent layout’s include
  46. <merge xmlns:android="..." Design attribute: menu Shows a menu in the

    layout preview android:layout_width="match_parent"
 android:layout_height="match_parent" ... </merge> > tools:menu="map"
  47. <merge xmlns:android="..." android:layout_width="match_parent"
 android:layout_height="match_parent" tools:menu="map" ... </merge> > Design attribute:

    menu Shows a menu in the layout preview
  48. <merge xmlns:android="..." Design attribute: actionBarNavMode Shows navigation in the action

    bar android:layout_width="match_parent"
 android:layout_height="match_parent" ... </merge> > tools:actionBarNavMode="tabs"
  49. <merge xmlns:android="..." android:layout_width="match_parent"
 android:layout_height="match_parent" tools:actionBarNavMode="tabs" ... </merge> > Design attribute:

    actionBarNavMode Shows navigation in the action bar …in theory
  50. <fragment xmlns:android="..." android:layout_width="match_parent"
 android:layout_height="match_parent" Design attribute: layout Previews a fragment’s

    layout ... /> tools:layout="@layout/fragment_main"
  51. <fragment xmlns:android="..." android:layout_width="match_parent"
 android:layout_height="match_parent" tools:layout="@layout/fragment_main" ... /> Design attribute: layout

    Previews a fragment’s layout
  52. Design attributes: list* Previews a ListView’s items, header and footer

    <ListView
 android:id="@+id/list"
 ... tools:listheader="@layout/list_header"
 tools:listitem="@layout/list_item"
 tools:listfooter="@layout/list_footer" />
  53. <ListView
 android:id="@+id/list"
 ... Design attributes: list* Previews a ListView’s items,

    header and footer tools:listheader="@layout/list_header"
 tools:listitem="@layout/list_item"
 tools:listfooter="@layout/list_footer" />
  54. Good read Tools of the Trade by Yours Truly https://goo.gl/hZv6S5

    https://goo.gl/sia3ms
  55. Good read Tools attributes http://goo.gl/lzd6YP

  56. Support annotations Require support-annotations dependency

  57. Support annotations Require support-annotations dependency Design attributes support-v4 (and thus

    v7) depends on it
  58. Support annotations Require support-annotations dependency support-v4 (and thus v7) depends

    on it
  59. public static String trim( return what.trim(); Nullability annotations @Nullable and

    @NonNull String what) { @Nullable }
  60. Nullability annotations @Nullable and @NonNull String what) { @Nullable public

    static String trim( return what.trim(); Method invocation may produce NullPointerException }
  61. public static String trim( if (what == null) {
 return

    "";
 
 return what.trim();
 Nullability annotations @Nullable and @NonNull String what) { } } @NonNull
  62. Nullability annotations @Nullable and @NonNull String what) { @NonNull }

    } public static String trim( if (what == null) {
 return "";
 
 return what.trim();
 Condition 'what == null' is always 'false'
  63. setMainTextColor(R.color.text_color);
 
 void setMainTextColor(
 textView.setTextColor(getColor(colorId)); Resource ID annotations A lot

    of @{resType}Res that enforce typing @Nullable Should pass resolved color instead of resource ID } int colorId) {
  64. setMainTextColor(R.color.text_color);
 
 void setMainTextColor(
 textView.setTextColor(getColor(colorId)); Resource ID annotations A lot

    of @{resType}Res that enforce typing @Nullable int colorId) { } @ColorRes
  65. Resource ID annotations @AnimatorRes @AnimRes @AnyRes @ArrayRes @AttrRes @BoolRes @ColorRes

    @DimenRes @DrawableRes @FractionRes @IdRes @IntegerRes @InterpolatorRes @LayoutRes @MenuRes @PluralsRes @RawRes @StringRes @StyleableRes @StyleRes @XmlRes
  66. setTextColor(R.color.text_color);
 
 private void setTextColor(
 ... RGB Color annotation @ColorInt

    requires color value, not ID } int color) { @ColorInt
  67. setTextColor(R.color.text_color);
 
 private void setTextColor(
 ... RGB Color annotation @ColorInt

    requires color value, not ID } @ColorInt int color) { Should pass resolved color instead of resource id here
  68. setValue(20); 
 void setValue(
 // Value must be in [0,

    10] Range annotations @FloatRange and @IntRange } int value) { @IntRange(from=0, to=10)
  69. setValue(20); 
 void setValue(
 // Value must be in [0,

    10] Range annotations @FloatRange and @IntRange } int value) { @IntRange(from=0, to=10) Value must be ≥ 0 and ≤ 10 (was 20)
  70. Range annotations setCoords(new int[]{42}); 
 void setCoords(
 // Value must

    be int[2] @Size for arrays, collections and strings } int[] value) { @Size(2) Value must be ≥ 0 and ≤ 10 (was 20)
  71. Range annotations setCoords(new int[]{42}); 
 void setCoords(
 // Value must

    be int[2] @Size for arrays, collections and strings } int[] value) { @Size(2) Value must be ≥ 0 and ≤ 10 (was 20) Size must be exactly 2
  72. int style; TypeDef annotations The issue with avoiding enums @IntRange(from=0,

    to=10) static final int STYLE_MATERIAL = 0;
 static final int STYLE_HOLOYOLO = 1; style = 21;
  73. @IntDef(value={STYLE_MATERIAL, STYLE_HOLOYOLO})
 @Retention(RetentionPolicy.SOURCE)
 @interface Style { } TypeDef annotations @interface

    definition: @IntDef and @StringDef @IntRange(from=0, to=10) static final int STYLE_MATERIAL = 0;
 static final int STYLE_HOLOYOLO = 1;
  74. style = 21; TypeDef annotations @interface usage @IntRange(from=0, to=10) Must

    be one of: STYLE_MATERIAL, STYLE_HOLOYOLO static final int STYLE_MATERIAL = 0;
 static final int STYLE_HOLOYOLO = 1; int style; @Style
  75. static final int STYLE_MATERIAL = 0;
 static final int STYLE_HOLOYOLO

    = 1; TypeDef annotations @interface usage @IntRange(from=0, to=10) @Style int style; style = 21; Must be one of: STYLE_MATERIAL, STYLE_HOLOYOLO
  76. Threading annotations Specify thread “affinity” for methods private void test()

    {
 textView.setText("Oops!"); @WorkerThread }
  77. Threading annotations Specify thread “affinity” for methods private void test()

    {
 textView.setText("Oops!"); @WorkerThread Method setText must be called from the UI thread, currently inferred thread is worker }
  78. Threading annotations Specify thread “affinity” for methods Method setText must

    be called from the UI thread, currently inferred thread is worker @MainThread @BinderThread @UiThread @WorkerThread
  79. “Architecture” annotations Contracts for methods invocation and overriding @CallSuper @CheckResult

    @VisibleForTesting
  80. Permissions annotations Specifies calling a method requires a permission startBluetoothScan();

    @RequiresPermission(Manifest.permission.BLUETOOTH) private void startBluetoothScan() { ... }
  81. Permissions annotations Specifies calling a method requires a permission @RequiresPermission(Manifest.permission.BLUETOOTH)

    startBluetoothScan(); private void startBluetoothScan() { ... } Missing permissions required by startBluetoothScan: android.permission.BLUETOOTH
  82. Proguard annotation Specifies a symbol should be kept by Proguard

    @Keep private void myMethod() { ... }
  83. Good read Improving Code Inspection with Annotations https://goo.gl/QLyf10

  84. Good read Support annotations http://goo.gl/3DTImU

  85. A & Q

  86. View debugging BONUS ROUND

  87. View debugging Built into the SDK since API 1

  88. View debugging Built into the SDK since API 1 ViewDebug

  89. View debugging Built into the SDK since API 1 ViewDebug

  90. public class MyCustomView extends View {
 private int fancyColor; Exported

    view properties Use @ExportedProperty @Nullable public int getFancyColor() {
 return fancyColor; } @ViewDebug.ExportedProperty
  91. public class MyCustomView extends View {
 private int fancyColor; Exported

    view properties Use @ExportedProperty @Nullable @ViewDebug.ExportedProperty public int getFancyColor() {
 return fancyColor; }
  92. Exported view properties Use @ExportedProperty @Nullable (
 category = "My

    category"
 ) public int getFancyColor() {
 return fancyColor; } @ViewDebug.ExportedProperty
  93. Good read ViewDebug JavaDoc http://goo.gl/v54umV

  94. A & Q (for real this time) (also, tweet questions

    @seebrock3r)
  95. Thank you! @seebrock3r +SebastianoPoggi rock3r Sebastiano Poggi Novoda, Android GDE

    #toolsOfTrade