Android, the life of your app

441 views
331 views

Published on

You can find the slides with speaker notes here : http://bit.ly/lifeofapp

During this talk we live the life of your app on the user's point of view.
The idea is to follow the user experience from the Play Store to the daily use, measure each time its frustration to find ways for us, as developers, to avoid them.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
441
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Android, the life of your app

  1. 1. THE LIFE OF YOUR APP
  2. 2. Eyal LEZMY SLIDES http://bit.ly/lifeofapp http://eyal.fr
  3. 3. AGENDA CODEURS EN SEINE 01 02 03 04 Install it Launch it Look at it Use it
  4. 4. 01 IT ALL STARTS ON THE PLAY STORE
  5. 5. MINIMISE PERMISSIONS Users should prefer apps requesting the least permissions Request only what your app requires 1/3 of apps request more permissions than they need
  6. 6. MINIMISE PERMISSIONS Users should prefer apps requesting the least permissions You don’t need permission Use ContentProviders
  7. 7. MINIMISE PERMISSIONS Permission are not required to launch another activity that has the permission
  8. 8. MINIMISE PERMISSIONS Need a contact?
  9. 9. MINIMISE PERMISSIONS Use the force, Luke
  10. 10. MINIMISE PERMISSIONS Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType(Phone.CONTENT_ITEM_TYPE); startActivityForResult(intent, MY_REQUEST_CODE); void onActivityResult(int requestCode, int resultCode, Intent data) { if (data != null) { Uri uri = data.getData(); if (uri != null) { Cursor c = getContentResolver().query(uri, new String[] {Contacts.DISPLAY_NAME, Phone.NUMBER}, null, null, null);} } } }
  11. 11. MINIMISE PERMISSIONS Start the contact app Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType(Phone.CONTENT_ITEM_TYPE); startActivityForResult(intent, MY_REQUEST_CODE); void onActivityResult(int requestCode, int resultCode, Intent data) { if (data != null) { Uri uri = data.getData(); if (uri != null) { Cursor c = getContentResolver().query(uri, new String[] {Contacts.DISPLAY_NAME, Phone.NUMBER}, null, null, null);} } } }
  12. 12. MINIMISE PERMISSIONS Start the contact app Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType(Phone.CONTENT_ITEM_TYPE); startActivityForResult(intent, MY_REQUEST_CODE); void onActivityResult(int requestCode, int resultCode, Intent data) { if (data != null) { Uri uri = data.getData(); if (uri != null) { Cursor c = getContentResolver().query(uri, new String[] {Contacts.DISPLAY_NAME, Phone.NUMBER}, null, null, null);} } } } Handle the result
  13. 13. MINIMISE PERMISSIONS Need an UUID? TelephonyManager.getDeviceId() Requires READ_PHONE_STATE permission Settings.Secure.ANDROID_ID Reset at every wipe Not applicable on multi user environment
  14. 14. MINIMISE PERMISSIONS Need an UUID? TelephonyManager.getDeviceId() Requires READ_PHONE_STATE permission Settings.Secure.ANDROID_ID Reset at every wipe Not applicable on multi user environment NO!
  15. 15. MINIMISE PERMISSIONS Need an UUID? Generate your own UUID and use Backup API ! String id = UUID.randomUUID(). toString();
  16. 16. MINIMISE PERMISSIONS Need an UUID? Generate your own UUID and use Backup API ! String id = UUID.randomUUID(). toString(); YES!
  17. 17. MINIMISE PERMISSIONS Android Backup API · API is available on all Android devices. · Manufacturors can implements their own transport and storage for the API · Each device as its own backup data · A new device will take a backup from a device associated with your google account. · IT'S NOT A SYNC API !
  18. 18. 02 THE FIRST LAUNCH
  19. 19. THE FIRST LAUNCH Make a good impression
  20. 20. THE FIRST LAUNCH Lets start!
  21. 21. http://cyrilmottier.com
  22. 22. THE FIRST LAUNCH <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.MyTheme" ... > We define our personal theme including the correct styles and colors
  23. 23. THE FIRST LAUNCH Let’s start... Again!
  24. 24. My Big BR D AN
  25. 25. LOADING ...
  26. 26. THE FIRST LAUNCH A bunch of data to insert? Use SQL transactions to save time!
  27. 27. THE FIRST LAUNCH Start transaction db.beginTransaction(); try{ for(int i=0; i<selectedIds.length; i++){ values.put(COLUMN_ID,selectedIds[i]); values.put(COLUMN_STARRED,starred); db.insert(TABLE_STARRED,null,values); db.yieldIfContendedSafely(); } db.setTransactionSuccessful(); } finally { db.endTransaction(); }
  28. 28. THE FIRST LAUNCH Start transaction db.beginTransaction(); try{ for(int i=0; i<selectedIds.length; i++){ values.put(COLUMN_ID,selectedIds[i]); values.put(COLUMN_STARRED,starred); db.insert(TABLE_STARRED,null,values); db.yieldIfContendedSafely(); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } End transaction
  29. 29. THE FIRST LAUNCH Start transaction db.beginTransaction(); try{ for(int i=0; i<selectedIds.length; i++){ values.put(COLUMN_ID,selectedIds[i]); values.put(COLUMN_STARRED,starred); db.insert(TABLE_STARRED,null,values); db.yieldIfContendedSafely(); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } End transaction Optimise multi-threaded insertion
  30. 30. THE FIRST LAUNCH Faster? Import directly, ready to use databases
  31. 31. THE FIRST LAUNCH ON THE SERVER · Create your db file using SQlite and fill it · Name your primary key columns "_id" · Create the table : "android_metadata" · And insert a single row containing the local if defined (ex: "en_US"), or open your database using : openDatabase(dbPath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.CREATE_IF_NECESSARY);
  32. 32. THE FIRST LAUNCH ON THE MOBILE · Grab the zipped database from assets or network · Unzip it to your getDatabaseDir() · Open the database Be careful of the SQLite version !
  33. 33. 03 LOOK AND FEEL
  34. 34. ? ? ?
  35. 35. LOOK AND FEEL HOTMAIL OUTLOOK.COM
  36. 36. LOOK AND FEEL SAME! HOTMAIL OUTLOOK.COM
  37. 37. LOOK AND FEEL FOLLOW THE GUIDELINES! http://d.android.com/design
  38. 38. LOOK AND FEEL Redesigned by Taylor Ling
  39. 39. LOOK AND FEEL By Microsoft
  40. 40. LOOK AND FEEL
  41. 41. LOOK AND FEEL
  42. 42. LOOK AND FEEL FOLLOW THE GUIDELINES! http://d.android.com/design
  43. 43. LOOK AND FEEL PLEASE! FOLLOW THE GUIDELINES! http://d.android.com/design
  44. 44. 04 A DAILY USE
  45. 45. SMOOTHEN YOUR UI UI Thread = Events+Draw 16 ms to draw a frame (~60 fps) Garbage Collector may take 10ms And stop all threads
  46. 46. SMOOTHEN YOUR UI Flatten the View Hierarchy · Use RelativeLayout instead of LinearLayout · Use the <merge/> tag when possible · Use hierarchyviewer to inspect your layouts
  47. 47. SMOOTHEN YOUR UI Avoid overdraws · Do not draw your background several times · Use the “GPU Overdraw” tool from Android 4.2
  48. 48. SMOOTHEN YOUR UI Avoid autoboxing Use SparseArray
  49. 49. SMOOTHEN YOUR UI Hashmap<Integer, Object> hashmap = new HashMap<Integer, Object>(); hashmap.put(1789, mRevolution); ... hashmap.get(1789); SparseArray<Object> sparseArray = new SparseArray<Object>(); sparseArray.put(1789, mRevolution); ... sparseArray.get(1789);
  50. 50. SMOOTHEN YOUR UI Hashmap<Integer, Object> hashmap = new HashMap<Integer, Object>(); hashmap.put(1789, mRevolution); ... hashmap.get(1789); new Integer(1789) SparseArray<Object> sparseArray = new SparseArray<Object>(); sparseArray.put(1789, mRevolution); ... sparseArray.get(1789);
  51. 51. SMOOTHEN YOUR UI Hashmap<Integer, Object> hashmap = new HashMap<Integer, Object>(); hashmap.put(1789, mRevolution); ... hashmap.get(1789); new Integer(1789) new Integer(1789) SparseArray<Object> sparseArray = new SparseArray<Object>(); sparseArray.put(1789, mRevolution); ... sparseArray.get(1789);
  52. 52. SMOOTHEN YOUR UI Hashmap<Integer, Object> hashmap = new HashMap<Integer, Object>(); hashmap.put(1789, mRevolution); ... hashmap.get(1789); new Integer(1789) new Integer(1789) SparseArray<Object> sparseArray = new SparseArray<Object>(); sparseArray.put(1789, mRevolution); ... sparseArray.get(1789); Low memory footprint and no more GC!
  53. 53. SMOOTHEN YOUR UI Load bitmap cleverly · Reuse it · Use sampling
  54. 54. SMOOTHEN YOUR UI BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inBitmap = myOldBitmap; Bitmap scaledBitmap = BitmapFactory.decode...(..., bitmapOptions); BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inSampleSize = sampleSize;
  55. 55. SMOOTHEN YOUR UI BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inBitmap = myOldBitmap; Bitmap scaledBitmap = BitmapFactory.decode...(..., bitmapOptions); Define the bitmap to reuse (API level 11) BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inSampleSize = sampleSize;
  56. 56. SMOOTHEN YOUR UI BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inBitmap = myOldBitmap; Bitmap scaledBitmap = BitmapFactory.decode...(..., bitmapOptions); Define the bitmap to reuse (API level 11) Use the option for loading BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inSampleSize = sampleSize;
  57. 57. SMOOTHEN YOUR UI BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inBitmap = myOldBitmap; Bitmap scaledBitmap = BitmapFactory.decode...(..., bitmapOptions); Define the bitmap to reuse (API level 11) Use the option for loading BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inSampleSize = sampleSize; Define the subsampling level (API Level 1)
  58. 58. PRESERVE THE BATTERY
  59. 59. PRESERVE THE BATTERY Screen: 1st item of consumtion 30 to 70% of the battery life
  60. 60. PRESERVE THE BATTERY WakeLocks Basically you don’t need it Only a few kind of applications should need to stay the device awake (Reader, Games, …) Think about the context Release wake lock if you have good assumptions that the user is not using your app anymore
  61. 61. PRESERVE THE BATTERY Geolocation GPS · Permission ACCESS_FINE_LOCATION · Drains a lot of power · Works offline Network location · · · · Permission ACCESS_COARSE_LOCATION Need to be online Fast Precise in urban area
  62. 62. PRESERVE THE BATTERY Geolocation Define a strategy · What is the needed precision for my app? · Define the measure interval wisely · Consider the GPS fix time Use Fused Location Provider On Google Play Services
  63. 63. PRESERVE THE BATTERY Network Radio drains a lot of power Group data to minimize the number of requests Use caching!
  64. 64. PRESERVE THE BATTERY private void enableHttpResponseCache() { try { long httpCacheSize = 10 * 1024 * 1024; // 10 MiB File httpCacheDir = new File(getCacheDir(), “http”); Class.forName(“android.net.http.HttpResponseCache”) .getMethod(“install”, File.class, long.class) .invoke(null, httpCacheDir, httpCacheSize); } catch (Exception httpResponseCacheNotAvailable) { Log.d(TAG, “HTTP response cache is unavailable.”); } } Enable cache, if available (API level 13) Or use a backport like HttpResponseCache
  65. 65. PRESERVE THE BATTERY Network Enable GZIP on the server 30 to 50% less trafic Use ETAGs
  66. 66. PRESERVE THE BATTERY
  67. 67. BE INSPIRED Gestures Text to Speech Accelerometer Voice recognition Proximity sensor Bluetooth NFC Direct Wifi Second Screen
  68. 68. BE INSPIRED Explore all the device’s possibilities
  69. 69. Thank You for your time ! SLIDES http://bit.ly/lifeofapp http://eyal.fr

×