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

Don't Make Me Repeat Myself

Don't Make Me Repeat Myself

A talk about intelligently re-using resources/code on Android. Given at AnDevCon.

Daniel Lew

May 01, 2012

More Decks by Daniel Lew

Other Decks in Programming


  1. Problem • I'm  lazy • Easy  to  figure  out  basics

     of  Android • Need  solu:ons  to  problems  quickly • End  up  fi>ng  square  peg  in  round  hole
  2. Goal • Save  effort  through  smart  Android  coding   prac:ces

    • Decrease  work  by  avoiding  duplica:on • Decrease  bugs  through  code  consistency
  3. Resource Qualifiers • All  files  under  /res/   are  resources

    • Format:  /res/<type>-­‐ <qualifier>/ • Qualifiers  can  be   applied  to  any   resource
  4. android:configChanges • ORen  abused  to  avoid  Ac:vity  restarts • Sidesteps

     the  resource  qualifier  system • Alterna:ves: –onSaveInstanceState() –Fragment.setRetainInstance() –onRetainNonConfigura:onInstance()  (deprecated   solu:on)
  5. onSaveInstanceState() protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(KEY, mVar); }

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { mVar = savedInstanceState.getBoolean(KEY); } }
  6. Retained Fragments protected void onCreate(Bundle savedInstanceState) { ! FragmentManager fm

    = getFragmentManager(); ! mInstance = (State) fm.findFragmentByTag(State.TAG); ! if (mInstance == null) { ! ! mInstance = new State(); ! ! mInstance.setRetainInstance(true); ! ! fm.beginTransaction().add(mInstance, State.TAG).commit(); ! } }
  7. <dimen> • Stores  a  scaling  value • Good  for  layout_width,

     layout_height,  textSize,   etc. <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:text="@string/hello" android:textSize="@dimen/my_text_size" />
  8. <integer> • Useful  for  weights • Change  a]ributes  with  constants

     (e.g.,   visibility) • Good  for  anima:on  :ming
  9. <integer> for weights <LinearLayout android:orientation="horizontal" > <View android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="@integer/weight1"

    /> <View android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="@integer/weight2" /> </LinearLayout>
  10. <integer> for attributes • In  /res/values/,  0  ==  "visible" <resources>

    <integer name="is_visible">0</integer> </resources> • In  /res/values-­‐<qualifier>/,  2  ==  "gone" <resources> <integer name="is_visible">2</integer> </resources>
  11. <bool> • Can  be  used  for  true/false  a]ributes • Useful

     for  determining  configura:on if (res.getBoolean(R.bool.is_landscape)) { tv.setText(R.string.landscape_detected); }
  12. <include> • Inflate  one  layout  file  in  another • Allows

     one  to  modify  part  of  a  layout  based   on  resource  qualifiers • Can  be  nested
  13. <merge> • Operates  like  <include>,  but  can  prevent   View

     duplica:on  in  hierarchy <merge> <!-- Insert include hierarchy --> </merge>
  14. <ViewStub> • Reduces  duplica:on  like  <include> • Inflate  Views  on

     demand  (lazy  infla:on) • Speeds  up  ini:al  infla:on <ViewStub android:id="@+id/stub_header" android:inflatedId="@+id/header" android:layout="@layout/include_header" android:layout_width="fill_parent" android:layout_height="wrap_content" />
  15. Repeated Inflation • Use  <include>  for  mul:ple  versions  of  the

     same   set  of  Views <LinearLayout> <include android:id="@+id/repeat_1" layout="@layout/include_repeat" /> <include android:id="@+id/repeat_2" layout="@layout/include_repeat" /> <include android:id="@+id/repeat_3" layout="@layout/include_repeat" /> </LinearLayout>
  16. Repeated Inflation • LayoutInflater  to  inflate  a  repeated  set  of

      Views private void addRow(ViewGroup container) { View view = getLayoutInflater() .inflate(R.layout.include_repeat, container, false); container.addView(view); }
  17. Plurals • <plurals>  lets  you  define  a  numerical  string  

    forma]er. • Logic  sits  in  resources,  not  in  code <plurals name="items_pluralization"> <item quantity="one">%d item</item> <item quantity="other">%d items</item> </plurals>
  18. Plurals Localization Lets  translators  handle  complex  corner  cases. <plurals name="items_pluralization">

    <item quantity="zero">%d items</item> <item quantity="one">%d item</item> <item quantity="two">%d items</item> <item quantity="few">%d items</item> <item quantity="many">%d items</item> <item quantity="other">%d items</item> </plurals>
  19. String Templating • String  forma>ng  built  into  Resources • Create

     templates  for  easy  modifica:on • Don't  be  too  clever  -­‐  localiza:on  can  be   tricky.
  20. String Templating • Resources: <string name="template_example">%1$s - %2$s</string> • Code:

    textView.setText(getString(R.string.templ ate, "First point", "Second point"));
  21. Strings as Keys • Tie  string  iden:fiers  to  keys •

    Works  for  preferences,  fragments,  more • Handy  conven:on:  do_not_translate.xml
  22. Identifier in Activity protected void onCreate(Bundle state) { ! super.onCreate(state);

    ! setContentView(R.layout.my_layout); ! FragmentManager fm = getFragmentManager(); ! mFragment = fm.findFragmentByTag( ! ! getString(R.string.tag_fragment)); }
  23. <string-array> • Use  referenced  @strings,  not  inline  strings! <string-array name="my_string_array">

    <item>@string/item_1</item> <item>@string/item_2</item> <item>@string/item_3</item> </string-array>
  24. When to Use Styles On Views • When  repea:ng  the

     same  View  a]ributes   along  similar  Views  (e.g.,  label  TextViews) • NOT  for  every  single  View • NOT  when  two  Views  happen  to  have  some   a]ributes  in  common
  25. Themes • Styles  applied  to  the  Applica:on  or  Ac:vity •

    Change  a]ribute  for  en:re  app/ac:vity • Some  styleables  only  applicable  to  themes
  26. Style Parenting • Styles  can  be  parented • Implicit  vs.

     explicit  parents <style name="Text" /> <style name="Text.Large" /> <style name="SmallText" parent="Text" />
  27. Styles and Resource Qualifiers • A]ributes  inside  of  styles  fall

     under  the   resource  qualifier  system • Styles  themselves  fall  under  the  resource   qualifier  system • Use  resource  qualifiers  to  swap  out  the   parent  style!
  28. Example: Holo Theme • Problem:  Holo  only  introduced  in  v11

    • Solu*on:  Use  resource  qualifiers  +  style   paren:ng  to  switch  which  parent  Theme  to   use  in  different  contexts
  29. • In  /res/values/themes.xml: <style name="MyTheme" parent="@android:style/Theme" /> • In  /res/values-­‐v11/themes.xml:

    <style name="MyTheme" parent="@android:style/Theme.Holo" /> • Bonus  (also  in  /res/values/themes.xml): <style name="AppTheme" parent="@style/MyTheme" />
  30. Nine-patches • Allows  intelligent  stretching  of  an  image • S:ll

     need  one  for  each  density,  as  the  non-­‐ stretchable  por:ons  are  scaled  otherwise.
  31. Shape Drawables • <shape>  lets  you  draw  simple  objects <shape

    android:shape="rectangle"> <gradient android:startColor="#F00" android:endColor="#00F" /> </shape>
  32. LayerDrawable • Layer  drawables  on   top  of  each  other

    • Example:  rounded   corners • Useful  w/  selector
  33. Simple Reference • You  can  reference  one  value  from  within

      another: <color name="alias_color">@color/ orig_color</color> • Works  for  any  simple  resource  type
  34. <item> resources • Reference  any  other  resource  with  <item>: <item

    name="aliased_resource" type="layout">@layout/orig_resource</ item> • Any  resource  type  can  be  aliased
  35. Layout Aliases • Problem:  handling  both  old  and  new  screen

      size  qualifiers • Old  style: –/layout-­‐small/, –/layout-­‐large/ • New  style: –/layout-­‐sw800dp/ –/layout-­‐h500dp/
  36. Layout Aliases • Define  two  alias  values  files. • /values-­‐large/aliases.xml:

    <item name="main" type="layout">@layout/ large</item> • /values-­‐sw600dp/aliases.xml: <item name="main" type="layout">@layout/ large</item>
  37. <activity-alias> • Create  two  different  Ac:vity  entries  in   AndroidManifest.xml

     that  point  to  the  same   Ac:vity. • Uses: –Alterna:ve  entrances  into  one  Ac:vity –Backwards  compa:bility
  38. Activity Inheritance • Suppose  you  want  to  apply  a  behavior

     to  all   your  Ac:vi:es • Problem:  you  have  a  mixture  of  Ac:vity,   ListAc:vity,  MapAc:vity,  etc • Solu:on:  Composi:on  over  inheritance
  39. Activity Inheritance 1.Create  an  Ac:vity  Helper  that  implements   func:onality.

    public class TrackingHelper { public void onResume() { // Tracking code } }
  40. Activity Inheritance 2.Add  the  helper  to  your  Ac:vity public class

    MyActivity extends Activity { private TrackingHelper mTrackingHelper = new TrackingHelper(); public void onResume() { super.onResume(); mTrackingHelper.onResume(); } }
  41. Widgets •Group  sets  of  related  Views  into  one  class •Easily

     reuse  Views  in  mul:ple  places  with   one  simple  interface
  42. Simple Widget • Split  Views  into  its  on  layout  file

    • Use  <include>  +  find,  or  inflate  in  the  widget   itself
  43. Complex Widget • Views  may/may  not  exist,  widget  handles  

    automa:cally. • Use  <item>  to  create  ids  ahead  of  :me  (no   conflicts)
  44. Libraries • Leverage  these  to  reuse  common   components  between

     your  applica:ons • Problem:  what  if  you  want  to  reskin  a   component  from  a  library? • Answer:  A]ributes  and  themes
  45. Styling Library Activities 1.Define  a]ributes  for  what  XML  values  

    you  want  to  customize  (usually  in   a]rs.xml). <resources> <attr name="myBackground" format="reference|color" /> </resources>
  46. Styling Library Activities 2.Link  to  those  a]ributes  in  the  library's

     XML. <LinearLayout android:layout_height="fill_parent" android:layout_width="fill_parent" android:background="?attr/ myBackground" />
  47. Styling Library Activities 3.In  the  applica:on  using  the  library,  create

     a   theme  which  defines  values  for  those   a]ributes. <style name="LibraryTheme"> <item name="myBackground">#000</item> </style>
  48. Styling Library Activities 4.Apply  that  theme  to  the  Applica:on  (or

      Ac:vity) <application android:icon="@drawable/icon" android:label="My App" android:theme="@style/LibraryTheme">
  49. Warning • If  you  try  to  access  an  a]ribute  that

     is  not   defined,  you  get  a  very  ugly  (and  difficult  to   debug)  explosion • Create  a  default  theme  that  applica:ons   using  your  library  can  extend  (to  avoid   explosions)
  50. Dynamic Resources • Problem:  data-­‐driven  apps  referencing   resources  leads

     to  duplicate  data  structures • Solu:on  #1:  getIden:fier() getResources().getIdentifier("drawableName" , "drawable", "com.mypackage.myapp"); • Solu:on  #2:  reflec:on Class res = R.drawable.class; Field field = res.getField("drawableName"); int drawableId = field.getInt(null);
  51. Logging • Problem:  repeatedly  disabling/tagging  logs • Log  wrapper  allows

     auto-­‐tagging  and  app-­‐ wide  enabling/disabling • My  open  source  version:  h]p://bit.ly/H7NpRi