47
Android Best Practices Anuradha Weeraman

Android Best Practices - Thoughts from the Trenches

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Android Best Practices - Thoughts from the Trenches

Android Best Practices

Anuradha Weeraman

Page 2: Android Best Practices - Thoughts from the Trenches

What makes a good Android app

● Responsiveness● Resource-conscious● User experience and UI● Co-exist and interact with other apps● Follows good engineering standards

Page 3: Android Best Practices - Thoughts from the Trenches

A classic

Page 4: Android Best Practices - Thoughts from the Trenches

Responsiveness

● Do not block the UI thread with heavy work● Offload them to a worker thread● Respond to user input within 5 seconds● Broadcast receiver must complete in 10 seconds● User perceives “slowness” if it takes more than 200ms● Always update the user on progress● Avoid modal views and dialogs● Render the main view and fill in data as it arrives

Page 5: Android Best Practices - Thoughts from the Trenches

Responsivenessprivate class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {

// Do the long-running work in here

protected Long doInBackground(URL... urls) {

int count = urls.length;

long totalSize = 0;

for (int i = 0; i < count; i++) {

totalSize += Downloader.downloadFile(urls[i]);

publishProgress((int) ((i / (float) count) * 100));

// Escape early if cancel() is called

if (isCancelled()) break;

}

return totalSize;

}

// This is called each time you call publishProgress()

protected void onProgressUpdate(Integer... progress) {

setProgressPercent(progress[0]);

}

// This is called when doInBackground() is finished

protected void onPostExecute(Long result) {

showNotification("Downloaded " + result + " bytes");

}

}

new DownloadFilesTask().execute(url1, url2, url3);

Page 7: Android Best Practices - Thoughts from the Trenches

Performance Pointers

Avoid creating short-term temporary objects if you can. Fewer objects created mean less-frequent garbage collection, which has a direct impact on user experience.

Avoid creating unnecessary objects

Page 8: Android Best Practices - Thoughts from the Trenches

Performance Pointers

If you don't need to access an object's fields, make your method static. Invocations will be about 15%-20% faster. It's also good practice, because you can tell from the method signature that calling the method can't alter the object's state.

Prefer static over virtual

Page 9: Android Best Practices - Thoughts from the Trenches

Performance Pointers

When declaring constants in a class, always use ‘static final’ as it reduces the amount of work that the VM has to do at runtime.

Use ‘static final’ for constants

static final int intVal = 42;

static final String strVal = "Hello,

world!";

Page 10: Android Best Practices - Thoughts from the Trenches

Performance Pointers

It's reasonable to follow common object-oriented programming practices and have getters and setters in the public interface, but within a class you should always access fields directly. Virtual method calls are expensive, much more so than instance field lookups. Direct field access is about 7x faster than invoking a trivial getter.

Avoid internal getters/setters

i = getCount()Replace

i = mCountWith

Page 11: Android Best Practices - Thoughts from the Trenches

Question time

public void zero() {

int sum = 0;

for (int i = 0; i < mArray.length; ++i) {

sum += mArray[i].mSplat;

}

}

public void one() {

int sum = 0;

Foo[] localArray = mArray;

int len = localArray.length;

for (int i = 0; i < len; ++i) {

sum += localArray[i].mSplat;

}

}

public void two() {

int sum = 0;

for (Foo a : mArray) {

sum += a.mSplat;

}

Place these three functions in ascending order of speed.

Page 12: Android Best Practices - Thoughts from the Trenches

Performance Pointers

ARM CPUs that Android devices use do not have an FPU and is therefore around 2x slower when performing floating point calculations than integers as the calculation is performed in software. Avoid using floating point wherever possible, and keep note of this when optimizing performance in hotspots.

Avoid using floating point

Page 13: Android Best Practices - Thoughts from the Trenches

Performance Pointers

Android libraries have been extensively optimized for the constrained runtime environment. Use the provided libraries for best performance. For example, System.arraycopy() is about 9x faster than a hand-coded loop in a JIT environment.

Use the libraries

Page 14: Android Best Practices - Thoughts from the Trenches

Performance Pointers

Apps that use native code from the Android NDK are not necessarily the most performant. There’s overhead associated with the Java-native transition and the JIT can’t optimize across these boundaries.

As a rule of thumb, use the NDK when you have existing codebases that you want to make available on the Android, and not for speeding up parts of your application.

Use native methods carefully

Page 15: Android Best Practices - Thoughts from the Trenches

Performance Pointers

Measure the performance of the app using ‘traceview’ and DDMS (now Android Device Monitor).

Always measure

Page 16: Android Best Practices - Thoughts from the Trenches

Resource-conscious

● Mobile devices are resource constrained environments● Your app must play nice in this environment● Respect user’s preferences● The devices may not have all the hardware you need● Release resources when you don’t need them

Page 17: Android Best Practices - Thoughts from the Trenches

Question time

What is a wake lock?

Page 18: Android Best Practices - Thoughts from the Trenches

Resource Pointers

A capability that can be used to drain your battery efficiently and quickly. Always ask the question, “Do I need to use a wake lock?”

● Use the minimum level possible, when required.- PARTIAL_WAKE_LOCK- SCREEN_DIM_WAKE_LOCK- SCREEN_BRIGHT_WAKE_LOCK- FULL_WAKE_LOCK

● Release as soon as you can● Specify a timeout

Don’t overuse wake locks

Page 20: Android Best Practices - Thoughts from the Trenches

Resource Pointers

The FULL_WAKE_LOCK has been deprecated in favor the FLAG_KEEP_SCREEN_ON attribute which is better at handling this when the user moves between apps and requires no special permission.

Don’t overuse wake locks

getWindow().addFlags(

WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

Page 21: Android Best Practices - Thoughts from the Trenches

Resource Pointers

Only transfer data in the background if it’s enabled by the user.

Respect user preferences

boolean backgroundDataEnabled =

connectivityManager.getBackgroundDataSetting()

Note: This is deprecated on ICS and above and will instead show getActiveNetworkInfo() as disconnected.

Page 22: Android Best Practices - Thoughts from the Trenches

Resource Pointers

● By default, the service would keep restarting when killed by the runtime

● By setting START_NOT_STICKY it would not

Allow the runtime to kill your service

@Override public int onStartCommand(Intent intent, int flags, int startId) { //TODO do something useful return Service.START_NOT_STICKY; }}

Page 23: Android Best Practices - Thoughts from the Trenches

Resource Pointers

As with activities the Android system may terminate the process of a service at any time to save resources. For this reason you cannot simple use a TimerTask in the service to ensure that it is executed on a regular basis.

Use receivers and alarms to trigger your service

Calendar cal = Calendar.getInstance();

Intent intent = new Intent(this, MyService.class);PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);

AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);// Start every 30 secondsalarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 30*1000, pintent);

Page 24: Android Best Practices - Thoughts from the Trenches

Resource Pointers

When scheduling updates, use inexact repeating alarms that allow the system to "phase shift" the exact moment each alarm triggers. If several alarms are scheduled to trigger at similar times, this phase-shifting will cause them to be triggered simultaneously, allowing each update to piggyback on top of a single active radio state change.

Use inexact alarms

int alarmType = AlarmManager.ELAPSED_REALTIME;

long interval = AlarmManager.INTERVAL_HOUR;

long start = System.currentTimeMillis() + interval;

alarmManager.setInexactRepeating(alarmType, start, interval, pi);

Page 25: Android Best Practices - Thoughts from the Trenches

Resource Pointers

● Services should only be running when needed● Perform the activity in an AsyncTask● Kill the service when the task is complete

Kill your own service when work is done

stopSelf()

Page 26: Android Best Practices - Thoughts from the Trenches

Resource Pointers

● Explicitly specify uses-feature node in the manifest for every hardware/software feature used in the app

● Mark essential features as required● Mark optional features as not required

Declared required hardware and check for availability when using them

<uses-feature android:name="android.hardware.bluetooth" />

<uses-feature android:name="android.hardware.camera" />

Page 27: Android Best Practices - Thoughts from the Trenches

Resource Pointers

Check for API availability before using features

PackageManager pm = getPackageManager();

boolean hasCompass = pm.hasSystemFeature(PackageManager.

FEATURE_SENSOR_COMPASS);

if (hasCompass) {

// do things that require the compass

}

Page 28: Android Best Practices - Thoughts from the Trenches

Question time

How does Google Play make use of the uses-feature declarations?

Page 29: Android Best Practices - Thoughts from the Trenches

Question time

Are permissions required anymore when the uses-feature element is present in the manifest?

Page 30: Android Best Practices - Thoughts from the Trenches

User experience & UI

● User experience should be your first priority● Don’t copy UI paradigms from other platforms● Respect user expectations on navigation● The back button should always navigate back through

previously seen screens● Navigating between application elements should be

easy and intuitive● Use notifications judiciously - time sensitive / involves

another person● Use dialogs for feedback, not notification

Page 31: Android Best Practices - Thoughts from the Trenches

UX/UI PointersRespect user expectations of navigation

Page 32: Android Best Practices - Thoughts from the Trenches

UX/UI Pointers

Don’t override the menu button to make it do something other than displaying the contextual menu. It’s important to keep the metaphors consistent to provide a good user experience.

Don’t override the menu button

Page 33: Android Best Practices - Thoughts from the Trenches

UX/UI Pointers

While it’s easy to build for just one orientation such as portrait, there are some devices where the orientation changes when the physical keyboard is activated. A good user experience needs to cater to different orientations intelligently.

Support both landscape and portrait modes

Page 34: Android Best Practices - Thoughts from the Trenches

UX/UI Pointers

● Start with vector or high res raster art

● Scale down and optimize for supported screens and resolutions

● Use device independent pixels● Use fragments to re-use design

elements across different form factors

● Optimize the layout for the available screen real-estate

Don’t make assumptions about screen size or resolutions

Page 35: Android Best Practices - Thoughts from the Trenches

Co-exist and interact with other apps

● Your app is just one of many on the device

● The more it gets integrated into the ecosystem of the device, the easier it is for the user and better the experience

Page 36: Android Best Practices - Thoughts from the Trenches

Integration Pointers

● Use intents to leverage other people’s apps● Can pass data back and forth between applications● Use intent filters to share functionality with other apps● Use content providers to expose access to an app’s

content for consumption by other apps and widgets

Leverage existing apps

Page 37: Android Best Practices - Thoughts from the Trenches

Follow good engineering practices

● Don’t use undocumented APIs!!● Android comes with a number of engineering tools for

ensuring technical quality of your app● Use these tools during development and testing to make

sure that your app follows good engineering practices and for troubleshooting performance issues that may degrade the user experience

Page 38: Android Best Practices - Thoughts from the Trenches

Question time

Name a tool that come with the Android SDK that can be used for performance analysis and profiling during

development?

Page 39: Android Best Practices - Thoughts from the Trenches

Static / structural analysis

● Android comes with a tool called lint that can be used for identifying and correcting structural problems with your code

● Each detection has an associated description and severity level so it can be prioritized

● Can be invoked directly from the command-line, automated build system or directly from Eclipse

Page 40: Android Best Practices - Thoughts from the Trenches

● Android comes with a tool called hierarchyviewer which is now part of the Android Device Monitor that can be used for analyzing layout rendering performance

● Can be used in combination with lint to discover and fix performance issues that affect responsiveness

● The Pixel Perfect window in hierarchyviewer can be used for getting the layout just right

Layout optimization

Page 41: Android Best Practices - Thoughts from the Trenches

● ‘traceview’ is a tool that can be used for viewing execution logs produced by an app for method profiling purposes.

● Traces can be created from within the code or from the DDMS tool, depending on how granular you want the traces

Profiling

// start tracing to "/sdcard/calc.trace"

Debug.startMethodTracing("calc");

// ...

// stop tracing

Debug.stopMethodTracing();

● ‘dmtracedump’ is an alternate tool that can be used for visualizing the call stack from trace log files

Page 42: Android Best Practices - Thoughts from the Trenches

Profiling● systrace helps you analyze how the execution of your

application fits into the larger Android environment, letting you see system and applications process execution on a common timeline. The tool allows you to generate highly detailed, interactive reports from devices running Android 4.1 and higher.

Page 43: Android Best Practices - Thoughts from the Trenches

● RoboGuice is a framework that brings the simplicity and ease of Dependency Injection to Android, using Google's own Guice library.

Dependency Injection

class AndroidWay extends Activity {

TextView name;

ImageView thumbnail;

LocationManager loc;

Drawable icon;

String myName;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

name = (TextView) findViewById(R.id.name);

thumbnail = (ImageView) findViewById(R.id.thumbnail);

loc = (LocationManager) getSystemService(Activity.

LOCATION_SERVICE);

icon = getResources().getDrawable(R.drawable.icon);

myName = getString(R.string.app_name);

name.setText( "Hello, " + myName );

}

}

class RoboWay extends RoboActivity {

@InjectView(R.id.name) TextView name;

@InjectView(R.id.thumbnail) ImageView thumbnail;

@InjectResource(R.drawable.icon) Drawable icon;

@InjectResource(R.string.app_name) String myName;

@Inject LocationManager loc;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

name.setText( "Hello, " + myName );

}

}

Page 44: Android Best Practices - Thoughts from the Trenches

Some bedtime reading

Page 45: Android Best Practices - Thoughts from the Trenches

YAMBA - Yet Another Micro-Blogging Application

Requirements

1. Build a Twitter-like micro blogging application.2. User can view a stream of statuses fetched from a server.3. User can update preferences to specify user’s details.4. The statuses are fetched from the server in the background and

persisted locally.5. The background process that fetches the statuses is started

when the device boots.6. The background process is started and stopped depending on

the available network connectivity.7. A timeline view shows the latest stream of statuses from local

storage.

Page 46: Android Best Practices - Thoughts from the Trenches

Question time

What are the structural building blocks in Android that can be used to build apps?

Page 47: Android Best Practices - Thoughts from the Trenches

YAMBA - Yet Another Micro-Blogging Application