• Like
Android, the life of your app
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Android, the life of your app

  • 236 views
Published

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

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
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
236
On SlideShare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
2
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. THE LIFE OF YOUR APP
  • 2. Eyal LEZMY SLIDES http://bit.ly/lifeofapp http://eyal.fr
  • 3. AGENDA CODEURS EN SEINE 01 02 03 04 Install it Launch it Look at it Use it
  • 4. 01 IT ALL STARTS ON THE PLAY STORE
  • 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. MINIMISE PERMISSIONS Users should prefer apps requesting the least permissions You don’t need permission Use ContentProviders
  • 7. MINIMISE PERMISSIONS Permission are not required to launch another activity that has the permission
  • 8. MINIMISE PERMISSIONS Need a contact?
  • 9. MINIMISE PERMISSIONS Use the force, Luke
  • 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. 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. 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. 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. 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. MINIMISE PERMISSIONS Need an UUID? Generate your own UUID and use Backup API ! String id = UUID.randomUUID(). toString();
  • 16. MINIMISE PERMISSIONS Need an UUID? Generate your own UUID and use Backup API ! String id = UUID.randomUUID(). toString(); YES!
  • 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. 02 THE FIRST LAUNCH
  • 19. THE FIRST LAUNCH Make a good impression
  • 20. THE FIRST LAUNCH Lets start!
  • 21. http://cyrilmottier.com
  • 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. THE FIRST LAUNCH Let’s start... Again!
  • 24. My Big BR D AN
  • 25. LOADING ...
  • 26. THE FIRST LAUNCH A bunch of data to insert? Use SQL transactions to save time!
  • 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. 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. 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. THE FIRST LAUNCH Faster? Import directly, ready to use databases
  • 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. 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. 03 LOOK AND FEEL
  • 34. ? ? ?
  • 35. LOOK AND FEEL HOTMAIL OUTLOOK.COM
  • 36. LOOK AND FEEL SAME! HOTMAIL OUTLOOK.COM
  • 37. LOOK AND FEEL FOLLOW THE GUIDELINES! http://d.android.com/design
  • 38. LOOK AND FEEL Redesigned by Taylor Ling
  • 39. LOOK AND FEEL By Microsoft
  • 40. LOOK AND FEEL
  • 41. LOOK AND FEEL
  • 42. LOOK AND FEEL FOLLOW THE GUIDELINES! http://d.android.com/design
  • 43. LOOK AND FEEL PLEASE! FOLLOW THE GUIDELINES! http://d.android.com/design
  • 44. 04 A DAILY USE
  • 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. 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. SMOOTHEN YOUR UI Avoid overdraws · Do not draw your background several times · Use the “GPU Overdraw” tool from Android 4.2
  • 48. SMOOTHEN YOUR UI Avoid autoboxing Use SparseArray
  • 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. 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. 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. 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. SMOOTHEN YOUR UI Load bitmap cleverly · Reuse it · Use sampling
  • 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. 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. 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. 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. PRESERVE THE BATTERY
  • 59. PRESERVE THE BATTERY Screen: 1st item of consumtion 30 to 70% of the battery life
  • 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. 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. 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. PRESERVE THE BATTERY Network Radio drains a lot of power Group data to minimize the number of requests Use caching!
  • 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. PRESERVE THE BATTERY Network Enable GZIP on the server 30 to 50% less trafic Use ETAGs
  • 66. PRESERVE THE BATTERY
  • 67. BE INSPIRED Gestures Text to Speech Accelerometer Voice recognition Proximity sensor Bluetooth NFC Direct Wifi Second Screen
  • 68. BE INSPIRED Explore all the device’s possibilities
  • 69. Thank You for your time ! SLIDES http://bit.ly/lifeofapp http://eyal.fr