72
THE LIFE OF YOUR APP

Android, the life of your app

Embed Size (px)

DESCRIPTION

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.

Citation preview

Page 1: Android, the life of your app

THE LIFE OF YOUR APP

Page 2: Android, the life of your app

Eyal LEZMY

http://eyal.fr

SLIDES http://bit.ly/lifeofapp

Page 3: Android, the life of your app

AGENDACODEURS EN SEINE

01

Install it

02

Launch it

03

Look at it

04

Use it

Page 4: Android, the life of your app

IT ALL STARTS ON THE PLAY STORE

01

Page 5: Android, the life of your app
Page 6: Android, the life of your app
Page 7: Android, the life of your app

Request only what your app requires

1/3 of apps request more permissions than they need

MINIMISE PERMISSIONS

Users should prefer apps

requesting the least

permissions

Page 8: Android, the life of your app

You don’t need permission

Use ContentProviders

MINIMISE PERMISSIONS

Users should prefer apps

requesting the least

permissions

Page 9: Android, the life of your app

Permission are not required to launch another activity that has the permission

MINIMISE PERMISSIONS

Page 10: Android, the life of your app

Need a contact?

MINIMISE PERMISSIONS

Page 11: Android, the life of your app

Use the force, Luke

MINIMISE PERMISSIONS

Page 12: Android, the life of your app

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);} }

}}

Page 13: Android, the life of your app

MINIMISE PERMISSIONS

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType(Phone.CONTENT_ITEM_TYPE);startActivityForResult(intent, MY_REQUEST_CODE);

Start the contact app

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);} }

}}

Page 14: Android, the life of your app

MINIMISE PERMISSIONS

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType(Phone.CONTENT_ITEM_TYPE);startActivityForResult(intent, MY_REQUEST_CODE);

Start the contact app

Handle the result

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);} }

}}

Page 15: Android, the life of your app

Need an UUID? TelephonyManager.getDeviceId()

Requires READ_PHONE_STATE permission

MINIMISE PERMISSIONS

Settings.Secure.ANDROID_IDReset at every wipeNot applicable on multi user environment

Page 16: Android, the life of your app

Need an UUID? TelephonyManager.getDeviceId()

Requires READ_PHONE_STATE permission

MINIMISE PERMISSIONS

Settings.Secure.ANDROID_IDReset at every wipeNot applicable on multi user environment

NO!

Page 17: Android, the life of your app

Need an UUID? Generate your own UUID and use

Backup API !

MINIMISE PERMISSIONS

String id = UUID.randomUUID().toString();

Page 18: Android, the life of your app

Need an UUID? Generate your own UUID and use

Backup API !

MINIMISE PERMISSIONS

String id = UUID.randomUUID().toString();

YES!

Page 19: Android, the life of your app

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 !

MINIMISE PERMISSIONS

Page 20: Android, the life of your app

THE FIRST LAUNCH02

Page 21: Android, the life of your app

Make a good

impression

THE FIRST LAUNCH

Page 22: Android, the life of your app

Lets start!

THE FIRST LAUNCH

Page 23: Android, the life of your app

http://cyrilmottier.com

Page 24: Android, the life of your app

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

Page 25: Android, the life of your app

Let’s start...Again!

THE FIRST LAUNCH

Page 26: Android, the life of your app

My Big

BRAND

Page 27: Android, the life of your app

LOADING ...

Page 28: Android, the life of your app

A bunch of data to insert? Use SQL transactions to save

time!

THE FIRST LAUNCH

Page 29: Android, the life of your app

THE FIRST LAUNCH

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();

}

Start transaction

Page 30: Android, the life of your app

THE FIRST LAUNCH

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();

}

Start transaction

End transaction

Page 31: Android, the life of your app

THE FIRST LAUNCH

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();

}

Start transaction

End transaction Optimise multi-threaded insertion

Page 32: Android, the life of your app

Import directly, ready to use databases

Faster?

THE FIRST LAUNCH

Page 33: Android, the life of your app

openDatabase(dbPath, null,SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.CREATE_IF_NECESSARY);

· 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 :

THE FIRST LAUNCH

ON THE SERVER

Page 34: Android, the life of your app

· Grab the zipped database from assets or network

· Unzip it to your getDatabaseDir()

· Open the database

THE FIRST LAUNCH

ON THE MOBILE

Be careful of the SQLite version !

Page 35: Android, the life of your app

LOOK AND FEEL03

Page 36: Android, the life of your app

? ? ?

Page 37: Android, the life of your app

LOOK AND FEEL

HOTMAIL OUTLOOK.COM

Page 38: Android, the life of your app

LOOK AND FEEL

HOTMAIL OUTLOOK.COM

SAME!

Page 39: Android, the life of your app

LOOK AND FEEL

FOLLOW THE GUIDELINES!http://d.android.com/design

Page 40: Android, the life of your app

Redesigned by Taylor Ling

LOOK AND FEEL

Page 41: Android, the life of your app

By Microsoft

LOOK AND FEEL

Page 42: Android, the life of your app

LOOK AND FEEL

Page 43: Android, the life of your app

LOOK AND FEEL

Page 44: Android, the life of your app

LOOK AND FEEL

FOLLOW THE GUIDELINES!http://d.android.com/design

Page 45: Android, the life of your app

LOOK AND FEEL

FOLLOW THE GUIDELINES!http://d.android.com/design

PLEASE!

Page 46: Android, the life of your app

A DAILY USE04

Page 47: Android, the life of your app

UI Thread =

Events+Draw 16 ms to draw a frame (~60 fps)

SMOOTHEN YOUR UI

Garbage Collector may take 10ms And stop all threads

Page 48: Android, the life of your app

Flatten the View

Hierarchy· Use RelativeLayout instead of LinearLayout

· Use the <merge/> tag when possible

· Use hierarchyviewer to inspect your layouts

SMOOTHEN YOUR UI

Page 49: Android, the life of your app

Avoid overdraws · Do not draw your background several times

· Use the “GPU Overdraw” tool from Android 4.2

SMOOTHEN YOUR UI

Page 50: Android, the life of your app

Use SparseArray

SMOOTHEN YOUR UI

Avoid autoboxing

Page 51: Android, the life of your app

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);

Page 52: Android, the life of your app

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);

Page 53: Android, the life of your app

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);

Page 54: Android, the life of your app

SMOOTHEN YOUR UI

Hashmap<Integer, Object> hashmap = new HashMap<Integer, Object>();hashmap.put(1789, mRevolution);...hashmap.get(1789);

new Integer(1789)new Integer(1789)

Low memory footprint and no more GC!

SparseArray<Object> sparseArray = new SparseArray<Object>();sparseArray.put(1789, mRevolution);...sparseArray.get(1789);

Page 55: Android, the life of your app

· Reuse it

· Use sampling

SMOOTHEN YOUR UI

Load bitmapcleverly

Page 56: Android, the life of your app

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;

Page 57: Android, the life of your app

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;

Define the bitmap to reuse (API level 11)

Page 58: Android, the life of your app

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;

Use the option for loadingDefine the bitmap to reuse (API level 11)

Page 59: Android, the life of your app

SMOOTHEN YOUR UI

BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();bitmapOptions.inBitmap = myOldBitmap;

Bitmap scaledBitmap = BitmapFactory.decode...(..., bitmapOptions);

Define the subsampling level (API Level 1)

BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();bitmapOptions.inSampleSize = sampleSize;

Use the option for loadingDefine the bitmap to reuse (API level 11)

Page 60: Android, the life of your app

PRESERVE THE BATTERY

Page 61: Android, the life of your app

Screen: 1st item of consumtion30 to 70% of the battery life

PRESERVE THE BATTERY

Page 62: Android, the life of your app

Basically you don’t need itOnly a few kind of applications should need to stay the device awake (Reader, Games, …)

Think about the contextRelease wake lock if you have good assumptions that the user is not using your app anymore

WakeLocks

PRESERVE THE BATTERY

Page 63: Android, the life of your app

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

Geolocation

PRESERVE THE BATTERY

Page 64: Android, the life of your app

Define a strategy· What is the needed precision for my app?· Define the measure interval wisely· Consider the GPS fix time

Use Fused Location ProviderOn Google Play Services

Geolocation

PRESERVE THE BATTERY

Page 65: Android, the life of your app

Radio drains a lot of powerGroup data to minimize the number of requests

Use caching!

Network

PRESERVE THE BATTERY

Page 66: Android, the life of your app

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

Page 67: Android, the life of your app

Enable GZIP on the server30 to 50% less trafic

Use ETAGs

Network

PRESERVE THE BATTERY

Page 68: Android, the life of your app

PRESERVE THE BATTERY

Page 69: Android, the life of your app

BE INSPIRED

Gestures Text to Speech Accelerometer

Voice recognition Proximity sensor Bluetooth

NFC Direct Wifi Second Screen

Page 70: Android, the life of your app

BE INSPIRED

Explore all the device’s possibilities

Page 71: Android, the life of your app
Page 72: Android, the life of your app

Thank You for your time !

http://eyal.fr

SLIDEShttp://bit.ly/lifeofapp