Android Airplane Mode

   Posted by: Jim White

Recently, I have been assisting a high school student - Ryan - with a school science project.  This bright and talented young man's project (which I have agreed not to disclose in detail) is building a mobile application for the iPhone and Android platforms.  Wow!  I think my high school science project involved trying to create electricity with a potato.  Of course my IQ and talents were more aligned with the vegetable family ... enough said on that matter.  Ryan on the other hand, has started to unravel the mysteries of two mobile platforms and coding on each of them by himself with just a little help from his dad and uncle.  This guy's got oodles of intelligence and a bright future ahead of him.  Fellow Android developers and users, rest assured that our future looks very bright.  The fact that Ryan is tackling such problems should also make us all feel good in that a PhD is not required to innovate in the mobile world.  A person with a strong desire a bit of work can make it happen.

One of the things that Ryan has asked me to help him with seemed like a great topic for this week's blog post.  His problem, and may be yours, is how to programmatically put an Android phone into airplane mode.  Airplane mode serves to cut all the communications and radio signals of the phone.  No phone calls.  No SMS messages.  No Bluetooth.  All of these services are out when a device is in airplane mode.  In fact, a list of all the affected "radios" that are terminated when a device is in airplane mode can be obtained through the AIRPLANE_MODE_RADIOS constant defined on Settings.System.  The code below demonstrates the use of this API to log the available radios of a device.

Log.i("Test",
        "List of radios:  "
                + Settings.System.getString(getContentResolver(),
                        Settings.System.AIRPLANE_MODE_RADIOS));

First - Get Permission

In order to be able to put the device in or out of airplane mode, the application must have WRITE_SETTINGS user permissions.  This permission allows an application to read or write the system settings that include airplane mode.  To request WRITE_SETTINGS add the <uses-permissions> element to the Android Manifest file as demonstrated below.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.intertech.Activities"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
 
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
    <!-- your components here -->
    </application>
</manifest>

Coding Airplane Mode On/Off

Airplane mode is an integer toggle setting.  It is either on (1) or off (0).  Use the putInt() method on Settings.System to change the airplane mode setting.  This method requires a ContentResolver (which can be obtained from the context) and the system setting to be set (which of course is the AIRPLANE_MODE_ON setting).  The code below demonstrates setting it on and off.

Settings.System.putInt(getContentResolver(),
                    Settings.System.AIRPLANE_MODE_ON, 1);  //  turn airplane mode on
Settings.System.putInt(getContentResolver(),
                    Settings.System.AIRPLANE_MODE_ON, 0);  // turn airplane mode off

Since it is a toggle, you generally want to know its existing state before turning it on or off.  Use the getInt() method on Settings.System to get the existing value.

Settings.System.getInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0);

Broadcast the Airplane Mode Update

After changing the system setting, but before airplane mode takes effect, you must broadcast (via Intent) that the mode has changed.  Create an Intent with the Intent.ACTION_AIRPLANE_MODE_CHANGED action.  Add the airplane mode "state" to the Intent and then broadcast the message.  Failure to broadcast this intent leaves the device in its current airplane mode setting.

Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", false);  //indicate the "state" of airplane mode is changed to on
sendBroadcast(intent);

A Clean and Total Example

You'll find an elegant way to check the setting, toggle the current airplane mode, and broadcast the mode change intent in a post here.  Below, I have borrowed a bit from that post, simplified it a bit, and provided an example activity method that could be setup to toggle airplane mode on a button press (via onClick listener callback).

public void airplaneModeOn(View view) {
    try {
        boolean isEnabled = Settings.System.getInt(getContentResolver(),Settings.System.AIRPLANE_MODE_ON, 0) == 1;
        Settings.System.putInt(getContentResolver(),Settings.System.AIRPLANE_MODE_ON, isEnabled ? 0 : 1);
        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        intent.putExtra("state", !isEnabled);
        sendBroadcast(intent);
    } catch (Exception e) {
        Toast.makeText(this, "exception:" + e.toString(), Toast.LENGTH_LONG).show();
    }
}

The results of executing this method via a simple activity (the button here is setup to trigger the airplaneModeOn method) is shown in the AVD images below.

SNAGHTML53f0355SNAGHTML53e0bce

And when you try to use the phone on the AVD with airplane mode on, you'll see that the AVD appropriately blocks the call.

SNAGHTML5401d7a

Wrap Up

So I hope this example helps you and my friend Ryan.  The Android API makes working with many of the devices facilities and services very easy.  Remember, if you have a need to learn more about Android, think about taking Intertech's Complete Android class.  Find out more details about our class here and contact Dan McCabe at 800-866-9884..

Android Action Bar from the Options Menu

   Posted by: Jim White

As of March 5, 2012 over 95% of devices accessing the Android Market (now called Google Play) use Android 2.3.7 or less (source for that fact can be found here).  Users (and application developers) of these devices have become accustomed to the options menu.  That is, the menu that pops up on the bottom (typically) of the device when the user presses the Menu button.  Below, an example set of 3 menu items on an options menu are displayed when the user pushes the menu button on the device.

SNAGHTML11d0f32

image

 

Bye Bye Menu Button

As of Android 3.0 (Honeycomb), the standard four Android buttons of Home, Back, Menu and Search are replaced by Home, Back and a Recent Apps button.  Below is a picture of Galaxy Nexus (running Android 4.0 offered by Verizon) that shows an example of the new 3 button system. 

image

Tablets, which run Android 3 and for which Android 3 was really created, have no hardware buttons. The three buttons (Home, Back, and Recent Apps) are offered as "virtual buttons" on the screen (see Motorola Xoom as an example of such device below).

image

In fact, and as a side note, the future of hardware buttons on Android platforms (smartphones, tablets, etc.) is questionable.  Many believe the time has come to move to only virtual buttons (see editorial comment here).  Regardless of whether the buttons are represented in hardware or virtually, the Menu button and the options menu associated to it are gone.  So, how does one provide the type of capability provided by the options menu on Android 3 and later devices?  The answer is through action bar.  In a recent blog post, Scott Main who is the lead tech writer for developer.android.com, warns developers that they need to start making this transition - and soon.

Transitioning to the Action Bar

The good news is that the transition from options menu to action bar is quite simple.  Indeed, the action bar provides for a lot more capability than the options menu.  Therefore, you can spend a lot of time on improving and upgrading your applications to take advantage of its full capability.  See the action bar documentation to look into all the action bar features.  In this post, however, I want to show you how easy it is to take a typical options menu and move it to an action bar, and then show you what that looks like to the user.  To begin, say your application has an options menu defined in an XML menu resource like that below.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
 
    <item android:id="@+id/courses" android:icon="@drawable/course"
        android:title="@string/courses" />
    <item android:id="@+id/scores" android:icon="@drawable/score"
        android:title="@string/scores" />
    <item android:id="@+id/handicap" android:icon="@drawable/handicap"
        android:title="@string/handicap" />
 
</menu>

In an application where the AndroidManifest.xml file suggests that the minimum version of the Android SDK is 10 (Android 2.3.3) , then the menu buttons appear as shown below in a smartphone AVD.

<uses-sdk android:minSdkVersion="10" />

image

If you were to simply change the minimum version of the SDK to be 11 (suggesting Android 3.0), then it might surprise you to see the AVD displays as shown below when you press the menu button.image

In order to use the new action bar, add an android:showAsAction attribute to your menu items.  The value of the showAsAction attribute can be any one of the values described in the table below.

showAsAction value option

Description

"always" Always have the item appear on the action bar (as opposed to being placed in the overflow menu when space is limited - see below).
"ifRoom" Have the item appear in the action bar, but only if there is room available on the action bar.  If there's not enough room, the item appears in the overflow menu.
"never" Never have the item appear in the action bar.  Always display the item on the overflow menu.

In the example below, the same menu is defined in XML, but this time with the showAsAction attribute is set for each item.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
 
    <item android:id="@+id/courses" android:icon="@drawable/course"
        android:title="@string/courses" android:showAsAction="ifRoom"/>
    <item android:id="@+id/scores" android:icon="@drawable/score"
        android:title="@string/scores" android:showAsAction="ifRoom"/>
    <item android:id="@+id/handicap" android:icon="@drawable/handicap"
        android:title="@string/handicap" android:showAsAction="ifRoom"/>
 
</menu>

This causes the action bar to display with the items' icons displayed in the bar.SNAGHTML174ccb8

You might notice only 2 of the 3 original menu items are displayed in the new action bar, and furthermore, the title string is missing.  Given the "ifRoom" value to the showAsAction attribute, Android determined there was only room for 2 of the options.  To get the other menu items, you must go to the "overflow menu."  To get to the overflow menu, press the Menu button on the AVD.  On actual devices, a soft options menu button appears as three vertical dots (see example below).  It should be noted that this allows for the "normal" options menu to be used although not recommended.

image

When the overflow menu button is clicked, the other (or overflow) menu items appear.

image

As for the menu item title, you can add the withText modifier to the attribute value.  If your menu items have a title and an icon only the icon is displayed in the action bar by default.  Add "withText" as shown below to include the text with the icon in the the action bar.  In this case, the screen is shown in landscape orientation (and with the overflow menu shown) in order to make sure there is room to seem some of the items with their text.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
 
    <item android:id="@+id/courses" android:icon="@drawable/course"
        android:title="@string/courses" android:showAsAction="ifRoom|withText"/>
    <item android:id="@+id/scores" android:icon="@drawable/score"
        android:title="@string/scores" android:showAsAction="ifRoom|withText"/>
    <item android:id="@+id/handicap" android:icon="@drawable/handicap"
        android:title="@string/handicap" android:showAsAction="ifRoom|withText"/>
 
</menu>

image

The Android documentation on action bars makes an important point with regard to the title and why you should always provide it even if you don't always use the "withText" modifier.

It's important that you always define android:title for each menu item?even if you don't declare that the title appear with the action item?for three reasons:

  • If there's not enough room in the action bar for the action item, the menu item appears in the overflow menu and only the title appears.
  • Screen readers for sight-impaired users read the menu item's title.
  • If the action item appears with only the icon, a user can long-press the item to reveal a tool-tip that displays the action item's title.

Creating, Inflating, and Reacting to Selection

In your activity code, you create and inflate the action bar in the same way that the options menu is created and inflated. Use the onCreateOptionsMenu method to create action bar items.  The onPrepareOptionsMenu method is called right before the menu is shown.  Given the action bar is always displayed, this method may not be called as often as it used to be with the options menu.  However, it will be called before the overflow menu is shown too.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.options, menu);
    return true;
}
 
public boolean onPrepareOptionsMenu(Menu menu) {
    //  preparation code here
    return super.onPrepareOptionsMenu(menu);
}

To react to an action bar item being selected, implement the onOptionsItemSelected method just as you would in the options menu case.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.courses) {
        startActivity(new Intent(this, CoursesActivity.class));
    }
    if (item.getItemId() == R.id.scores) {
        startActivity(new Intent(this, ScoresActivity.class));
    }
    if (item.getItemId() == R.id.handicap) {
        startActivity(new Intent(this, HandicapActivity.class));
    }
    return super.onOptionsItemSelected(item);
}

Removing the Action Bar

You can remove the action bar for any activity.  In the AndroidManifest.xml file, simply set the theme of the activity to Theme.Holo.NoActionBar.

<activity
  android:label="@string/app_name"
  android:name=".GolfAndroidActivity" android:theme="@android:style/Theme.Holo.NoActionBar">
  <intent-filter >
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>

Programmatically, you can also get the action bar with a call to getActionBar().  Once obtained, you can request to hide it.  Android adjusts the layout/display of the screen when the action bar is removed.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    ActionBar bar = getActionBar();
    bar.hide();
}

A copy of a little demo app (as used in this post) is available for you to try out the action bar.  You'll find the Eclipse project (zipped) for download here.

Wrap up

Again, there are a number of additional and more advanced features that come with the new action bar. This includes split action bars, application navigation, action view (a widget that appears in the action bar as a substitute for an action item's button) and navigational tabs to name a few. As you explore the action bar as a replacement for the options menu, you might also find this new UI mechanism replaces other complex UIs like the TabWidget.

Feel like you need to learn Android soon?  Come join me at Intertech for Android training.  Find details about the class here.

Android Logging

   Posted by: Jim White

Android is a Java platform, albeit a slightly different Java platform.  As such, many new Android developers I encounter are at first confused by Android's logging features.  Admittedly, it is a bit different that some of the logging APIs and apparatus one encounters in Java SE or Java EE.  So I'm going to attempt to clarify some of Android's logging capability and also highlight some very interesting points about how logging works.

The Log class

First off, logging is accomplished through Android's android.util.Log class.  There are a collection of static methods that are called on the class itself to write to what is called the LogCat.  The documentation for the Log class can be found here, but below are the more significant methods.

Android Log method Purpose

e(String tag, String message)

Log an error

w(String tag, String message)

Log a warning

i(String tag, String message)

Log an informational message

d(String tag, String message)

Log a debug statement

v(String tag, String message)

v stands for verbose.  Log verbose forms of the informational messages

wtf(String tag, String message)

My favorite - indicating the Android developers truly have a sense of humor.  Log a failure (probably critical) that was never expected/anticipated to occur.  According to the documentation, wtf stands for what a terrible failure.  Ahhh - sure.  This method was added with Android 2.2 (API 8).  So it is not available in all Android environments.

Note, there are additional methods and those above are overloaded, but this is enough to get you started logging.

As you can see by the methods' purpose, each method allows you to suggest the severity and importance of the log message.  The purpose of the first parameter to these methods, the tag parameter, is to identify the component that originated the log message.  The tag string can be very helpful in helping to filter out log messages (more on this topic below).  The second parameter to the Log methods is the message to be deposited in the LogCat.

As a matter of good Android development practice, create static final String constants to keep the tags consistent.

private static final String VIEW_TAG = "ContactDisplayActivity";

Use the Log class and its methods from anywhere in your Android code to add messages to the log file like the Activity below.

public class ContactDisplayActivity extends Activity {
 
    private static final String VIEW_TAG = "ContactDisplayActivity";
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.v(VIEW_TAG, "In the onCreate method");
        // your code here
    }    
}

The LogCat

So where do all those log messages go?  Android maintains a circular buffer (i.e. file) for log messages, stack traces, etc.  This file is located in /dev/log/main on the device (or Android Virtual Device during testing).  It is circular in that the file is maintained within a fixed size.  As new messages come in and the buffer/file fills up, old messages are pulled off the file (making room for the new messages).  The size of the LogCat buffer varies per device.  You can use the adb tool to see the size of the log (see details about adb here).  Call the following command:

adb logcat -g

Below is an example result indicating my device has a buffer size of 64K.

SNAGHTML67d6a1

Accessing LogCat

You access LogCat for an AVD or on an actual device (via USB cable) from either DDMS or an adb shell.  You can even use the same tools to control entries and formatting to the LogCat file.  See here for more details on reading and writing to the log.  If you use Eclipse, there is a DDMS perspective that provides a LogCat view for viewing (and filtering

image

In fact, these tools allow you to filter the log so as to be able to find relevant entries.  You can filter by message severity (as shown below).

image

You can also create other custom filters that filter messages by tag (and the reason why establishing good tags is good Android developer convention), message, process id, or application name.

image  SNAGHTML7f51e9

Turn Logging Off in Production

While access to the log file is limited (via the tools mentioned), you still have to be careful in that it is very easy to hook up a real device to a laptop via USB and see the information logged.  A Belgian bank create a very large security concern by logging information from a server to the log file during development and forgetting to remove the logging when the application went to production.  See here for the details of the story.  No doubt, you will hear and see of other such security concerns.  In fact, the Android Developer site provides some prudent guidance regarding the preparation of an application before it is ready to be released.  In that guidance, they tell us to "Make sure you deactivate logging and disable the debugging option before you build your application for release."

Turning Off (or Down) Logging

To stop debugging, you can remove Log calls in your code.  Alternately, you can conditionalize Log calls and thereby allow a single variable (or set of variables) to help control what (if anything) gets logged.

public static boolean LOG_ON = true;

if (LOG_ON) Log.e(VIEW_TAG, "error message goes here");

The adb can be used to temporarily set the log level as shown below, but the emphasis here is on temporary.

adb shell setprop log.tag.MyAppTag WARN

As a final alternative, you can also use a tool such as ProGuard to strip out logging statements.  ProGuard is a tool that shrinks, optimizes, and obfuscates Android Java code and is integrated into Android build systems.  You can learn more about these options from a nice StackOverflow thread here.

Why not System.out.println()

In "normal" Java, you may have used System.out.println() (and System.err) calls to drop debug and other log calls into the standard output (and standard error).  Good ol' System.out still works in Android, but it should be avoided.  First of all, by default, System.out.println( ) calls are routed to an alternate /dev/null file.  These log statements can be rerouted to the LogCat file with some additional configuration.  However, another reason why you may find System.out.println() less than helpful is that these println() messages are tagged with default "System.out" tags and with info (I) level priority.  So it is not as easy to determine what component launched the logging and the severity may not be inline with the info level attributed to the log message.

image

Log4j (and other such common Java logging packages)

For those more familiar with Log4J or SLF4J logging packages, you will find these frameworks are also available in Android.  In fact, their Android versions serve as a wrapper to the LogCat functionality.  You'll find Log4j for Android here and SLF4J for Android here.

Other Android Logging Secrets

There are a couple of other secrets to Logging that are often missed by Android developers.  In fact, these are not secrets but information that is buried a little bit in the Android documentation.

As mentioned already, all logging should be removed or at least reduced prior to shipping any Android application.  But you might be interested to know that debug log messages are compiled in to the Android code, but get stripped at runtime.  This is not the case with verbose log statements.  Therefore, as the documentation says, "Verbose should never be compiled into an application except during development."  (Reference:  http://developer.android.com/reference/android/util/Log.html).

Another little hidden gem of knowledge deep in the documentation is that there are actually several circular log files.  Log messages go to /dev/log/main, but there exist telephony logs, event logs and system logs as well.  These can be found in /dev/log/radio, /dev/log/events and /dev/log/system respectively.  Use the following command to view these logs.

adb logcat -b <alternate log name like radio>

Wrap Up

Hopefully, this post can help you navigate your way around the Android log capability.  If you are just starting out and would like to learn more about Android, please join me for Complete Android at Intertech.  Contact Dan McCabe in our office for details on our next public class offering.

How to Build, Package, and Deploy Android Apps with Maven Part 1, Setup

   Posted by: Jeff Jensen

Build Need

I'm crazy for automated builds, to enable repeatable builds, continuous integration and deployment, automated unit and integration tests, quality tools and metrics (e.g. automated code reviews), and more.  So it was only natural for me to want the same functionality when working on Android apps.

Recently, I setup Maven to build the Android product I was working on.  I have used Maven for many years, back to the Maven 1.x days (I was one of the last three committers to work on and release Maven 1.1), and always "must-have" a reproducible automated build of the products we're working on.  There are a number of worthy build tools (before using Maven, I used Ant; recently, I have begun experimenting with Gradle), and, whether you like Maven or not, one has to appreciate Maven's large ecosystem.  When encountering a need, usually a reasonable Maven solution already exists.  Thankfully, this is true for Android build needs!

In the past, what I found lacking was a comprehensive checklist of what is needed to fully setup a Maven and Eclipse environment for Android, so I took my notes, added some explanatory words, and made this post for reference.  I will make subsequent posts on how to effectively use these tools; in the meantime, here is how to setup the environment.

Solution

There are two Android Maven plugins to use:

  1. Maven Android Archetypes: Use this plugin to generate skeletal Android project(s) directories and files; a very helpful quick start.  If you are familiar with Maven archetypes, this plugin is like the others and you already know how to use it.  It has a few archetype choices as to the Android product source organization.
  2. Android Maven Plugin: Use this plugin to manage the development lifecycle phases - compile, unit test, package, deploy, and integration test the Android app's artifacts.  This plugin is the workhorse - used all the time.  It also has features to process the apk with ProGuard, deploy and run integration tests on an emulator or device, and use Scala as the programming language.

There are three Eclipse plugins to use:

  1. Android's Eclipse plugin, ADT (Android Development Tools): The Android team-supplied Eclipse plugin to help with app development.  This is a very useful plugin!  You probably already have this installed for existing Android development.
  2. m2eclipse: This is a Maven to Eclipse integration plugin.  It is very useful when using Eclipse with Maven.  This is one of my mandatory plugins for all projects that use Maven and Eclipse.  Note that newer versions are named m2e.
  3. m2e-android: Use this Eclipse plugin for integration between m2eclipse and the ADT Eclipse plugin.  The key feature is it allows m2eclipse/Maven to manage the Eclipse project but also have it as an Android project type - the Eclipse Android plugin is not in affect on a project otherwise.  In addition to the installation procedure outlined in its documentation, this plugin resides in the Eclipse Marketplace.  It requires m2eclipse 1.0.0 or newer.

Optional

  1. Maven Android SDK Deployer: Many of the Android jars are in the Maven Central repository (the ones with source code available), which mitigates the need for this plugin.  However, for the Android versions that Central does not have (at the time of this writing, versions 11, 12, and 13 are not in Central, but 14 is; source code availability is the problem), consider using this Maven plugin to install the Android jars into your local and remote Maven repositories (local is the one on your development-workspace PC; remote is your personal, team's, or corporate artifact repository, such as Nexus).  Note: this includes extras and add-ons.

    Installing the jars is a very infrequent activity - once per Android platform.  When working on a team, only one person needs to deploy the jars to the artifact repository as Maven will automatically retrieve them from the repository for the rest of the team. 

    In new SDK releases, Google has renamed some directories and moved some files for the prior releases.  Therefore, it sometimes requires uninstalling some packages and reinstalling them with the Android SDK manager for the Maven Android SDK Deployer to work correctly (refer to the notes in its read me).  You'll know to do this when encountering missing files due to the directory names don't match.  I've found it easiest to simply remove and reinstall all Android SDK items with the latest tool version (the download time is less than my manual-research-and-fix time!); this makes the Deployer work well as it stays current with how the latest SDK Manager Tool organizes the files for all releases.
  2. Android SDK Fido: Maven plugin to obtain the Android source and create a jar of it, particularly for browsing in an IDE.  When the source is also deployed to Maven Central and m2eclipse configured to automatically download and link jar sources to the jar dependencies in Eclipse, this plugin is not necessary.

Setup

Thankfully, each tool has pretty good documentation, so I won't repeat the details here.  Assuming Maven and Eclipse are already installed, configured, and proven to work, follow these steps:

  1. Install and configure the Android SDK.  Note: I suggest installing to a directory without a space in the name (e.g. the default on Windows is "C:\Program Files..." - note the space in the directory name) as I've encountered tooling issues when the path is not properly quoted.
  2. Install m2eclipse Eclipse plugin. Note that m2eclipse ships with Eclipse Indigo (referred to as m2e), so no installation required for that and newer Eclipse versions.
  3. Install Android's Eclipse plugin, ADT.  Requires setting the Android SDK location, so is useful to install after installing the SDK.  Be sure to configure the SDK Location via Window --> Preferences --> Android, otherwise build errors will occur.
  4. Install the m2e-android plugin.
  5. If the Android dependencies do not exist in Maven Central, then use the Maven Android SDK Deployer to deploy/install them in your installation.

Conclusion

The above should be enough to setup an Eclipse and Maven development environment for Android work.  In part 2, I'll describe creating new and modifying existing project configurations with these tools.

Maven-enabling Android apps brings its powerful functionality such as dependency management, release tasks, quality and metric tools, artifact management, continuous integration, and more, to the management of Android apps.

While typically using the IDE for interactive work, having a Maven-zed build for Android apps is very useful for initial setup, dependency management, CI, and releasing.

The tools described here make this all possible; we owe a big thanks to the people who created and maintain these tools.

By the way, check out our Complete Android Training class and let us know if we can help with your build and test solutions!

Android Widget Size

   Posted by: Jim White

When teaching Android, I find students confused by the many "size" or dimensional properties on Android TextView and various descendent widgets like Button, CheckBox, EditText, etc.  Often, the size of any widget can be dictated by its layout, content or other aspect.  But you can directly set the size by property.  Unfortunately, there a number of properties that determine the size of these widgets.

Units of Measure

What might add to the confusion is that the dimensions (height and width for example) can be specified in one of many different units of measure in the layout resource file.  Specifically, the height and width can be specified in pixels, density-independent pixels, scaled-independent pixels, inches, millimeters or em.  Inches and millimeters are probably straight forward enough.  However, the fact that there are three types of pixel definitions leads to questions about the differences among the other options.

Density-independent pixel

The pixel unit of measure refers to the actual number pixels on the screen.  Because the size and number of pixels can vary greatly across devices, widget height and width can vary when using pixels to determine the widget size.  A density-independent pixel is an abstract unit of measure.  It is based on a screen with a density of 160 pixels (or dots) per inch (dpi).  The formula is physical pixel = density-independent pixel * (160/ system dpi).  So, if you had a device with 320 pixels (dots) per inch, 1 density-independent pixel would equal 2 physical pixels.

Scaled-independent pixel

Scaled-independent pixel is like the density-independent pixel unit of measure.  However, scaled-independent pixels are also scaled by the user's font size preference. When using a widget (like EditText or TextView) that displays text, an adjustment may be made for the text as part of the widget display.  At the default font size settings, 1 scaled-independent pixel = 1 density-independent pixel.  However, this can change if the user sets the font size to be larger or smaller.

Developers are actually encourage to use the density-independent (or scaled-independent) unit of measure when defining widgets because it allows the widgets in an applications to preserve the appearance of physical size across many different sized devices.  In other words,  your widgets are automatically scaled on screens with different densities so that the look/feel of the user interface is preserved. 

For more information regarding the various pixel units of measure, see here.

EM

An em is a unit of measure derived in the field of typography (the art and technique of arranging type).  Originally, the unit was derived from the width of the capital letter 'M' (thus the name - and the way you pronounce this unit of measure).  What an em defines is the proportion of a given letter's width and height with respect to the point size.  The em should be the same for all fonts at a specified point size - providing a font/typeface independent unit of measure.  For example, in a 16 point typeface, 1 em = 16 points.  See here for more information on the em unit of measure.

Unit of Measure Abbreviations

When specifying a size in inches, millimeters, pixels, density-independent pixels, or scaled-independent pixels (all but EM), abbreviations are used.  The table below provides the abbreviation and an example dimension setting.

Unit of Measure Abbreviation Example
inches in "0.5in"
millimeters mm "20mm"
pixels px "100px"
density-independent pixels dp or dip "100dp" or "100dip"
scaled-independent pixels sp "100sp"

Physical Height/Width Properties

With an understanding of the units of measure, a better look at the widget size can be accomplished.  There are indeed several properties which control the physical dimensions of TextView (and all subclass) widgets.  These include the following properties:

  • height/width
  • maxHeight/minHeight
  • maxWidth/minWidth
  • ems
  • minEms/maxEms
  • textSize

Height/Width

The first two properties, height and width, set the specific height and width of the associated view.  In the example below, both the height and width are set to 100 pixels.  [Note:  programmatically, setHeight(int) and setWidth(int) sets these widget properties.  However, these methods only work in the pixel unit of measure.]

   1: <Button android:text="Push me now" android:id="@+id/button1"
   2:         android:layout_width="wrap_content" android:layout_height="wrap_content" android:height="100px" android:width="100px"></Button>

image

Layout Affect

Remember, when using layout ViewGroup (like LinearLayout), the layout often dictates the height and/or width of a widget.  In the example below, the height and width are set to 100 pixels, but the layout_width and layout_height are set to fill_parent.  This has an overriding effect and causes the button to be displayed with nothing close to the 100x100 pixel sizes.

   1: <Button android:text="Push me now" android:id="@+id/button1"
   2:     android:layout_width="fill_parent" android:layout_height="fill_parent"
   3:     android:height="100px" android:width="100px"></Button>

image

Max and Mins

The height and width properties call for the widget to be a specific size (when not affected by layout management).  The maxHeight/MinHeight and maxWidth/MinWidth can be used instead of the height/width properties.  Min and max properties inform Android what the maximum (at most) and minimum (at least) sizes can be for a widget.  Some layouts and the presence/non-presence of contained text can impact the dimensions of a widget.  These properties help to ensure the minimum and maximum width/height.

Unless the height and/or width are set between their respective min/max values, you don't want to use the height or width property with min/max properties.  In fact, you will find that the min/max properties override the height/width properties.  In the example below, note the minHeight/maxHeight properties are set to 100 and 200 pixels respectively.  When the height is set to 10px, it has no effect.

   1: <Button android:text="Push me now" android:id="@+id/button1"
   2:     android:layout_width="wrap_content" android:layout_height="wrap_content"
   3:     android:minHeight="100px" android:maxHeight="200px" android:height="10px"></Button>

image

If the height property is set to a value between min/max, then it dictates the size of the widget.  Here, the height is set to 150, between the min and max values of 100 and 200 pixels.

   1: <Button android:text="Push me now" android:id="@+id/button1"
   2:     android:layout_width="wrap_content" android:layout_height="wrap_content"
   3:     android:minHeight="100px" android:maxHeight="200px" android:height="150px"></Button>

image

TextSize

Widgets, like the push button, often have associated text.  The textSize property can and often does affect the size of not only the text displayed but also the associated widget.  Notice what happens to the button when the size of text is set to 100 pixels.  The corresponding button grows to meet the text demands.

   1: <Button android:text="Push me now" android:id="@+id/button1"
   2:     android:layout_width="wrap_content" android:layout_height="wrap_content"
   3:     android:textSize="100px"></Button>

image

However, when the height and width are set (either directly or with min/max properties), the textSize setting is overridden.  In the example below, the textSize is still set to 100 pixels, but the height is set to 10 pixels.  You can't even read the text anymore because the height of the resulting button is too small to display it.

   1: <Button android:text="Push me now" android:id="@+id/button1"
   2:     android:layout_width="wrap_content" android:layout_height="wrap_content"
   3:     android:textSize="100px" android:height="10px"></Button>

image

Using EMS

Special properties (and setters/getters from a programmatic perspective) are used to provide an EM dimension.  Below are two images, one with the ems value set to 10 and the other set to 20.

   1: <Button android:text="Push me now" android:id="@+id/button1"
   2:     android:layout_width="wrap_content" android:layout_height="wrap_content"
   3:     android:ems="20"></Button>

image

image

 

Don't use the height/width with ems values.   The height/width will override the ems values.

   1: <Button android:text="Push me now" android:id="@+id/button1"
   2:     android:layout_width="wrap_content" android:layout_height="wrap_content"
   3:     android:ems="20" android:height="100px" android:width="100px"></Button>

image

Wrap up

With all these "dimensional" properties and the ways they can be impacted by the layout, content, unit of measure, etc. its no wonder people can be a little confused on how to set the dimensions of an Android TextView (or descendent) widget.  Hopefully this post can help you figure out what works best for your mobile application need.  If you are looking for more help on developing Android  applications, consider taking Intertech's Complete Android training (see here for more details and contact Dan McCabe at dmccabe@intertech.com to reserve a seat).

Android Layout and ID Attribute

   Posted by: Jim White

By Jim White (Director of Training and Instructor)

In Android, there are two ways to construct Activities (Activities make up the bulk of the graphical user interface associated with Android applications).  You can programmatically add View and ViewGroup components (i.e. "widgets") to the Activity in Java program code.  However, the programmatic approach is typically reserved for more dynamic and/or complicated UI scenarios.  The alternate (and typical) way to construct an Activity is to use XML layout files.

When building the layout file, many people learning Android are often confused by the android:id attribute used in the definition of many components.  In this post, I attempt to clarify the what's and why's of the ID attribute.

Why an ID?

When defining your layout in XML, you may first be surprised to learn that the android:id is optional!  You only need to add an android:id attribute to any View component in the layout file when you want to reference the associated component.  That is, you want to reference the component in your Java code or when defining layout in XML.

Using the android:id Reference in Java Code

Sometimes, you define your Activity user interface in XML (through layout files), but then use Java code to make changes to the Android components.  For example, in the layout shown below an Activity's layout includes an EditText widget.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   3:     android:orientation="vertical" android:layout_width="fill_parent"
   4:     android:layout_height="fill_parent">
   5:     <EditText android:text="Hi there" android:id="@+id/GreetingText"
   6:         android:layout_width="wrap_content" android:layout_height="wrap_content"></EditText>
   7:     <Button android:text="Push Me" android:id="@+id/HelloButton"
   8:         android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="buttonPushed"></Button>
   9: </LinearLayout>

image

For example sake, say you wanted to change the text in the EditText widget when the user clicks the "Push Me" button.  The Java code to accomplish this work first needs to get a reference to the EditText instance displayed on the user interface.  In order to get a reference to the EditText instance (using the Activity's method findViewById()), you need the EditText to be defined with an android:id.  In this example, the id of the EditText view is GreetingText as defined by the attribute:  android:id="@+id/GreetingText".

Now Java code in the Activity can get a reference to the view and update its text when the the button is pushed (as exemplified below).

   1: public void buttonPushed(View v) {
   2:     EditText greetingText = (EditText) findViewById(R.id.GreetingText);
   3:     greetingText.setText("Hello yourself");
   4: }

Using the android:id Reference In Layout XML

Once a view is defined in XML, the view can also be referenced by other view components in a layout file via the android:id.  For example, what if the LinearLayout above were instead made a RelativeLayout.  In a RelativeLayout, views can be positioned on the screen relative to the position of another view or the parent view.  However, in order to indicate where a view should be placed in reference to another view, the android:id is needed to provide reference.  In the example below, the Push Me button is placed to the right of the EditText view.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   3:     android:layout_width="fill_parent" android:layout_height="wrap_content">
   4:     <EditText android:text="Hi there" android:id="@+id/GreetingText"
   5:         android:layout_width="wrap_content" android:layout_height="wrap_content"></EditText>
   6:     <Button android:text="Push Me" android:id="@+id/HelloButton"
   7:         android:layout_width="wrap_content" android:layout_height="wrap_content"
   8:         android:onClick="buttonPushed" android:layout_toRightOf="@id/GreetingText"></Button>
   9: </RelativeLayout>

Notice that the Push Me button, uses the EditText android:id to reference the view in order to position itself to the right of the EditText view (android:layout_toRightOf="@id/GreetingText").

image

Why the @+

Ok, so now you know why and how android:id's are used.  The next question is usually about the special symbols used in defining and referencing the android:id.  "What's with the @+ and @ in front of the android:id attribute when defining or referencing a view like EditText above?"

Use @+ on the first occurrence of a given android:id in a layout (XML) file.  It might be in the definition of the view or it might be in a reference - which ever is first.  In the example above, the EditText view is defined before the Button.  So the @+ is used on the android:id attribute in EditText.  However, if the Button was defined first, the @+ would be used on the relative layout positioning in the Button (as shown below.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   3:     android:layout_width="fill_parent" android:layout_height="wrap_content">
   4:     <Button android:text="Push Me" android:id="@+id/HelloButton"
   5:         android:layout_width="wrap_content" android:layout_height="wrap_content"
   6:         android:onClick="buttonPushed" android:layout_toRightOf="@+id/GreetingText"></Button>
   7:     <EditText android:text="Hi there" android:id="@id/GreetingText"
   8:         android:layout_width="wrap_content" android:layout_height="wrap_content"></EditText>
   9: </RelativeLayout>

The plus sign (+) indicates to the Android SDK's aapt tool (which is automatically invoked through Eclipse) that this is a new resource name.  Therefore, the aapt knows that it must add the reference (in this case GreetingText) to the generated R.java file.  Below, you can see the GreetingText id added to the R.java file for this simple demonstration project.

   1: /* AUTO-GENERATED FILE.  DO NOT MODIFY.
   2:  *
   3:  * This class was automatically generated by the
   4:  * aapt tool from the resource data it found.  It
   5:  * should not be modified by hand.
   6:  */
   7:  
   8: package com.intertech;
   9:  
  10: public final class R {
  11:     public static final class attr {
  12:     }
  13:     public static final class drawable {
  14:         public static final int icon=0x7f020000;
  15:     }
  16:     public static final class id {
  17:         public static final int GreetingText=0x7f050001;
  18:         public static final int HelloButton=0x7f050000;
  19:     }
  20:     public static final class layout {
  21:         public static final int main=0x7f030000;
  22:     }
  23:     public static final class string {
  24:         public static final int app_name=0x7f040001;
  25:         public static final int hello=0x7f040000;
  26:     }
  27: }

Subsequent references to the id can drop the "+" and just use the android package namespace (as in the case of the original Push Me button for relative positioning in the example above).

Some Special android:ids

Note that there are some special built-in android:ids.  The android:id for a ListView of a ListActivity is one such example.  That is, if your Activity is a subclass of ListActivity, you don't usually need a layout (the main view is just the list shown in the ListActivity).  However, if you want to customize the underlying layout and/or ListView, you  need to identify the associated ListView with @android:id/list so the ListActivity knows which view is the main list for the activity.

As another example, a tabbed view often requires components identified by android:id/tabhost, android:id/tabs and android:id/tabcontent.

Wrap Up

For more information about the definition and use of ids in Android layouts and code, see developer.android.com/guide/topics/resources/layout-resource.html#idvalue.  If you are looking for more help on developing Android  applications, consider taking Intertech's Complete Android training (see here for more details and contact Dan McCabe at dmccabe@intertech.com to reserve a seat).  Or, if you need mobile application consulting help, contact Ryan McCabe at rmccabe@intertech.com to get started.

Windows Phone 7 Video - Part Two

   Posted by: Intertech

This is part two of our Windows Phone 7 video from our Mobile Devcon:

Windows Phone 7 Video - Part One

   Posted by: Intertech

This is part one of our Windows Phone 7 Video from our Mobile DevCon:

Click here to see Part Two of the video.

Android Bootable Background Processes

   Posted by: Jim White

By Jim White (Director of Training and Instructor)

Last week, I had the pleasure of spending the week on the east coast teaching Android to a team that is getting ready to develop prototype mobile apps on tablet platforms.  My class was filled with a bunch of talented/smart guys that raised a lot of great questions.  The questions ranged from details on the API to architectural issues.  Over the next few weeks, I thought I would share some of their great questions (and answers I found) through my blog entries.

The first, from Steve, was a question on if it was possible to setup an Android background service to kick off when the hosting device boots up?  The answer is yes, and how to do it is covered below.

Create the Service

First, create your Android service (a class that extends android.app.Service).  For example sake, my demonstration service uses an AsyncTask to establish an Internet connection and check for the availability of a certain web site.  The AsyncTask returns a boolean indicating whether connectivity can be established or not and then the service raises a notification in the status bar to alert the device owner about the site availability.

Here is the code for my example service.

   1: package com.intertech.service;
   2:  
   3: import java.util.concurrent.ExecutionException;
   4: import java.util.concurrent.TimeUnit;
   5: import java.util.concurrent.TimeoutException;
   6:  
   7: import android.app.Notification;
   8: import android.app.NotificationManager;
   9: import android.app.PendingIntent;
  10: import android.app.Service;
  11: import android.content.Context;
  12: import android.content.Intent;
  13: import android.os.IBinder;
  14: import android.util.Log;
  15:  
  16: public class ConnectionCheckerService extends Service {
  17:  
  18:     private ConnectionTask task;
  19:  
  20:     @Override
  21:     public IBinder onBind(Intent arg0) {
  22:         return null;
  23:     }
  24:  
  25:     @Override
  26:     public void onCreate() {
  27:         super.onCreate();
  28:         Log.v("ConnectionChecker", "Connection Checker created");
  29:     }
  30:  
  31:     @Override
  32:     public int onStartCommand(Intent intent, int flags, int startId) {
  33:         Log.v("ConnectionChecker", "Connection Checker started");
  34:         task = new ConnectionTask();
  35:         task.execute();
  36:         notifyConnectionStatus();
  37:         return super.onStartCommand(intent, flags, startId);
  38:     }
  39:  
  40:     @Override
  41:     public void onDestroy() {
  42:         task.cancel(true);
  43:         Log.v("ConnectionChecker", "Stopping ConnectionChecker");
  44:         super.onDestroy();
  45:     }
  46:  
  47:     private void notifyConnectionStatus() {
  48:         Log.v("ConnectionChecker", "Getting task results.");
  49:         while (true) {
  50:             try {
  51:                 Boolean result = task.get(1000, TimeUnit.MILLISECONDS);
  52:                 Context context = getApplicationContext();
  53:                 PendingIntent contentIntent = PendingIntent.getService(context,
  54:                         0, null, 0);
  55:                 Notification notification = new Notification(R.drawable.icon,
  56:                         "Connection Status", System.currentTimeMillis());
  57:                 if (result) {
  58:                     notification.setLatestEventInfo(context,
  59:                             "Connection Service",
  60:                             "Intertech connection available!", contentIntent);
  61:                 } else {
  62:                     notification
  63:                             .setLatestEventInfo(context, "Connection Service",
  64:                                     "Intertech connection not available",
  65:                                     contentIntent);
  66:                 }
  67:                 NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  68:                 notificationManager.notify(1, notification);
  69:                 Log.v("ConnectionChecker", "Task results displayed.");
  70:                 break;
  71:             } catch (TimeoutException e) {
  72:                 Log.v("ConnectionChecker", "Task work not completed.");
  73:             } catch (InterruptedException e) {
  74:                 Log.v("ConnectionChecker", "Task work interrupted.");
  75:                 break;
  76:             } catch (ExecutionException e) {
  77:                 Log.v("ConnectionChecker", "Task work failed.");
  78:                 break;
  79:             }
  80:         }
  81:         task.cancel(true);
  82:     }
  83: }

And here is the code for the associated AsyncTask.  I use a separate thread (through the AsyncTask) in this example just to remind you that you probably want to use threads to conduct most work in Android.  While this example is simple, your startup task(s) may be more complex and therefore really require the threading.

   1: package com.intertech.service;
   2:  
   3: import java.io.IOException;
   4:  
   5: import org.apache.http.HttpResponse;
   6: import org.apache.http.client.ClientProtocolException;
   7: import org.apache.http.client.methods.HttpGet;
   8: import org.apache.http.impl.client.DefaultHttpClient;
   9: import org.apache.http.params.BasicHttpParams;
  10: import org.apache.http.params.HttpConnectionParams;
  11: import org.apache.http.params.HttpParams;
  12:  
  13: import android.os.AsyncTask;
  14: import android.util.Log;
  15:  
  16: public class ConnectionTask extends AsyncTask<Void, Void, Boolean> {
  17:  
  18:     private final String LIST_URL = "http://www.intertech.com";
  19:  
  20:     @Override
  21:     protected Boolean doInBackground(Void... arg0) {
  22:         Log.v("ConnectionTask", "Checkinig...");
  23:         HttpParams params = new BasicHttpParams();
  24:         HttpConnectionParams.setConnectionTimeout(params, 4000);
  25:         HttpConnectionParams.setSoTimeout(params, 7000);
  26:         DefaultHttpClient client = new DefaultHttpClient(params);
  27:         HttpGet get = new HttpGet(LIST_URL);
  28:         HttpResponse res;
  29:         try {
  30:             res = client.execute(get);
  31:         } catch (ClientProtocolException e) {
  32:             Log.v("ConnectionTask", "Unsuccessfully hit Intertech site");
  33:             return false;
  34:         } catch (IOException e) {
  35:             Log.v("ConnectionTask", "Unsuccessfully hit Intertech site");
  36:             return false;
  37:         }
  38:         int code = res.getStatusLine().getStatusCode();
  39:         if (code != 200) {
  40:             Log.v("ConnectionTask", "Unsuccessfully hit Intertech site");
  41:             return false;
  42:         }
  43:         Log.v("ConnectionTask", "Successfully hit Intertech site");
  44:         return true;
  45:     }
  46:  
  47: }

Create a Broadcast Receiver

Android services need something to kick them off.  Typically, services are created and started by activities or even other services.  In this case, since the device is booting, no other application component exists to start your service.  Create a Broadcast Receiver to start on boot of the device and then kickoff the service once started.

Broadcast receivers receive and react to announcements (intents).  Think simple ?listener? or ?event handler.?  They are great for doing small pieces of work in response to an external stimulus.  Announcements like the battery is low, download is complete, etc. can be picked up and reacted to by a Broadcast receiver.  Broadcast receivers are alive for just a short period ? to process the intent.  In this case, one will be used to react to the completion of the boot process.

Here is the code for the service-starting broadcast receiver.

   1: package com.intertech.service;
   2:  
   3: import android.content.BroadcastReceiver;
   4: import android.content.Context;
   5: import android.content.Intent;
   6: import android.util.Log;
   7:  
   8: public class ConnectionCheckerStarter extends BroadcastReceiver {
   9:  
  10:     @Override
  11:     public void onReceive(Context context, Intent intent) {
  12:  
  13:         if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
  14:             Intent serviceIntent = new Intent(context, ConnectionCheckerService.class);
  15:             context.startService(serviceIntent);
  16:         } else {
  17:             Log.e("ConnectionChecker", "Received unexpected intent " + intent.toString());
  18:         }
  19:     }
  20:  
  21: }

Register the Broadcast Receiver in the Manifest

With the service and the broadcast receiver now built, the last step is to register both components in the AndroidManifest.xml file.  Registering the service is easy as it takes no special configuration (with the exception of INTERNET user permissions for the AsyncTask for this example).  Registering the broadcast receiver, however, requires the receiver have an intent-filter for android.intent.action.BOOT_COMPLETED.  This intent is broadcast by Android after the system has finished booting.  Furthermore, user permission must be granted to receive the intent.  Here is the manifest XML code to register both the service and receiver as well as their required user permissions.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <manifest xmlns:android="http://schemas.android.com/apk/res/android"
   3:     package="com.intertech.service" android:versionCode="1"
   4:     android:versionName="1.0">
   5:     <application android:icon="@drawable/icon" android:label="@string/app_name">
   6:         <service android:name=".ConnectionCheckerService" android:label="ConnectionCheckerService" />
   7:         <receiver android:label="ConnectionCheckerStarter" android:name=".ConnectionCheckerStarter">
   8:             <intent-filter>
   9:                 <action android:name="android.intent.action.BOOT_COMPLETED" />
  10:             </intent-filter>
  11:         </receiver>
  12:     </application>
  13:     <uses-permission android:name="android.permission.INTERNET" />
  14:     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  15: </manifest> 

Results

With this application installed on a device, the service now starts after the device boots - thanks to the receiver.  In this example, the user doesn't see any visual display, save the status bar notification as shown below.

image image

A check of the LogCat indicates the service was successfully started during the boot process.

image

Wrap up

If you are looking to learn Android, please consider signing up for Intertech's Complete Android class (see here for details).  Our next public offering of the class will be held July 26-29.  Sign up today by contacting Dan McCabe at dmccabe@intertech.com

Easy Memory Management in Objective-C (iPhone / iPad)

   Posted by: Jason Shapiro

One of the reasons developers try to avoid learning Objective-C is in regard to its memory management (or rather, its lack of automation). 

I'm going to cut right to the chase: in basic, single threaded applications, memory management really isn't all that awful, and with a few simple rules, you can avoid most of the common mistakes made.

Allocating & Deallocating Memory

When an object is created, space needs to be allocated to store it on the heap (an area of memory for objects).  When that object is no longer in use, it should be deallocated from the heap in order to allow other objects to occupy that space.  This act of deallocation runs two great risks:

  • Forgetting to deallocate some memory before the pointer has dropped out of scope causes a "memory leak."  This means that the memory space is still occupied, despite the fact that it is no longer able to be used (or, for that matter, released).
  • Deallocating space before it's finished being used produces bugs which can be very difficult to track down.  If you have multiple pointers which are referencing the same object, you obviously don't want one of the pointers to remove the object while others are still using it! Unfortunately, the moment an exception occurs could be light years away from when the deallocation took place (hence the difficulty in locating the source of the problem).

Retain & Release

Luckily, with Objective-C, allocating is easy (you simply call "alloc" on the class you wish to create an instance of):

   1:  Customer *cust = [[Customer alloc] init];

Allocating not only creates the object and a place for it in memory, it also adds a single "retain count."  This count is used to determine whether or not an object should be deallocated.  As long as an object has a positive "retain count," it will remain on the heap.  Retain counts can be added explicitly by calling "retain" on a pointer.

   1:  [cust retain];

[Detailed rules on when you should add a retain count are discussed below.]

This "retain count" means that you will never have to deallocate an object yourself.  Instead you "release" an object that you've allocated (or became "an owner of" - more on that below), when you are finished. 

   1:  [cust release];

Every time a "release" message is received, the retain count is decremented.  The memory, however, will not be deallocated until the retain count has reached zero.  This helps reduce errors that would occur by accidentally deallocating an object while it is still "on active duty."

The Golden Rule: Symmetry

If you only remember one thing from this article, let it be this: If you are an owner of an object you MUST release the object when you have finished.  Likewise, if you are not an owner of an object, you MUST NOT release the object.  Therefore what you are looking for is symmetry in your code.  Retain -> Release.  That's it.  All of the other rules and use cases derive from this simple concept.  The next natural questions are:

  • What does it mean to be an owner?
  • When do I want to become an owner?
  • How do I become an owner?

What Does It Mean to be an Owner?

You're the owner of an object when your code has added a retain count to the referenced object.  This retain count could have been added directly (by calling "retain" on the pointer):

   1:  [cust retain];

... or indirectly by calling a "creation" function - more on that below.

When Do I Want to Become an Owner?

You are an owner of any object you create, whether you want to be, or not (again, more on that below).  In addition to that scenario, you'll generally want to become an owner when you are keeping the object beyond the scope of a single function (as an instance variable).  If you aren't an owner of an instance variables that points to an object, you run the risk that the object will be deallocated before you are finished using it.  Therefore, it's important to make sure you add a retain count for all instances variables that point to objects (unless you already added one implicitly, by calling a "creation" function). There are other exceptions & less common situations that you may run into as well, but this is the big one to remember.  

How Do I Become an Owner?

As stated above, you can become an owner of an object by calling the retain function.

You also become an owner by calling a "creation" function.  This is a function that not only returns a pointer to an object, it also adds a retain count on your behalf.

You can recognize a "creation" function by its name: it will start with, or simply be, one of these words: "Alloc," "New," "Copy," or "mutableCopy."  Since a "creation" function adds a retain count on your behalf, you are implicitly the owner of that object, and must eventually call "release."

It is generally assumed that if these words do not appear in the name of the function, and you haven't called "retain" on the pointer, you are not an owner of the object.  Therefore you should NOT release the object when you are finished using it.

   1:  NSString *myStr1 = [[NSString alloc] initWithString:@"Intertech" ];
       // An owner of the NSString (alloc) -- you must eventually call "release."
   2:  NSString *myStr2 = [[NSString stringWithString:@"Intertech"]; 
// NOT an owner of the NSString. -- you should NOT call "release."

Autorelease

When a function has a return value of a pointer to an object that it creates, the retain count needs to be handled in a special way.   For example, look at the following code... What's wrong with it?

   1:  -(Customer *) customer
   2:  {
   3:      Customer *cust = [[Customer alloc] init];
   4:      return cust;
   5:  }

We've broken the golden rule!  We've created an object with "alloc" (therefore adding a retain count), but we haven't released it before the "cust" pointer has fallen out of scope!  So how about this example... any better?

   1:  -(Customer *) customer
   2:  {
   3:      Customer *cust = [[Customer alloc] init];
   4:      [cust release];
   5:      return cust;
   6:  }

Well... now we have symmetry (retain -> release), however it's possible that the Customer object will be deallocated before the caller is able to use and/or retain it!

To get around this problem, Objective-C gives us a special kind of release called "Autorelease."  This function provides a deferred release, meaning we have given up ownership, but the object won't be released until a later time.  It does this by adding the release to an "autorelease pool."  You'll notice that this pool is automatically created and "drained" in your main() function by Xcode:

   1:  int main (int argc, const char * argv[])
   2:  {
   3:      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   4:   
   5:  // ...
   6:   
   7:     [pool drain];
   8:     return 0;
   9:  }

Therefore, you typically don't need to manage the pool yourself.  Instead, simply call "autorelease" when you have created an object in a function (unless your function is a "creation" function, which means the name should start with the one of the "creation" names: "Alloc," "New," "Copy," or "mutableCopy."  In that case, the caller would expect you to leave the retain count on their behalf).

   1:  -(Customer *) customer
   2:  {
   3:      Customer *cust = [[Customer alloc] init];
   4:      return [cust autorelease];
   5:  }

 

The Dealloc Function

When your object has been released enough times that the "retain count" has hit zero, the OS will deallocate your object from memory.  However, most objects that you create will be composed of pointers to other objects.  Consider the following interface:

   1:  @interface Customer : NSObject {}
   2:  @property (nonatomic, retain) FullName *custName;
   3:  @property (nonatomic, retain) Address *custAddr;
   4:  @end

When the customer is deallocated, what happens to the FullName and Address objects?  We wouldn't want to have the OS blindly deallocate these two objects, in case they are still in use by other blocks of code.  Instead, we should be given the opportunity to remove our retain count on these properties (if appropriate) before the Customer object is deallocated.  This is done through a special function called "dealloc."  It is your responsibility to create this function and release all retained instance variables (a call to the parent dealloc should be made at the very end of this function):

   1:  -(void) dealloc
   2:  {
   3:      [custName release];
   4:      [custAddr release];
   5:      [super dealloc];
   6:  }

Putting it together

Here is an example that contains several memory management problems.  See if you can find them all:

   1:  #import "FullName.h"
   2:  @interface Customer : NSObject {
   3:      FullName *_custName;
   4:  }
   5:  - (Customer *) customer;
   6:  - (FullName *) custName;
   7:  - (void) setCustName: (FullName *) newValue;
   8:   
   9:  @end
  10:   
  11:  @implementation Customer
  12:   
  13:  - (Customer *) customer
  14:  {
  15:      Customer *cust = [[Customer alloc] init];
  16:      return cust;
  17:  }
  18:   
  19:  - (FullName *) custName
  20:  {
  21:      [_custName retain];
  22:      return _custName;
  23:  }
  24:   
  25:  - (void) setCustName: (FullName *) newValue
  26:  {
  27:      _custName = newValue;
  28:  }
  29:   
  30:  - (void) dealloc
  31:  {
  32:      [super dealloc];
  33:  }
  34:   
  35:  @end

Problem #1: The Customer function on lines 13 - 17 has broken symmetry.  It creates an object with "alloc" but does not "autorelease" it.  Remember, when a function creates and returns an object, it should call autorelease, rather than release (for details, review the "Autorelease" section above).

Corrected:

   1:  - (Customer *) customer
   2:  {
   3:      Customer *cust = [[Customer alloc] init];
   4:      return [cust autorelease];
   5:  }

Problem #2: The custName function on lines 19 - 23 adds a retain count, but doesn't release it.  In fact, there is no real reason to add a retain count here, since we haven't created a method that uses one of the four "creation" names ("add," "new," "copy," and "mutableCopy"). 

Corrected:

   1:  - (FullName *) custName
   2:  {
   3:      return _custName;
   4:  }

Problem #3:  The setCustName: function on lines 25 - 28 are storing an instance variable, but are not retaining the reference.  Without a retain, it is possible the object will be deallocated before we are finished using it.  In this case, we need to release the old value and retain the new value.  Don't worry about whether or not there is already an old value set for this instance variable.  Unlike other languages (such as the NullPointerException in Java), Objective-C will quietly ignore the "release" call if nothing is there.

Corrected:

   1:  - (void) setCustName: (FullName *) newValue
   2:  {
   3:      [_custName release];
   4:      _custName = [newValue retain];
   5:  }

Problem #4:  We forgot to release our instance variable in the dealloc method!

Corrected:

   1:  - (void) dealloc
   2:  {
   3:      [_custName release];
   4:      [super dealloc];
   5:  }

P.S. - Use Your Tools!

While following the rules described above will drastically reduce the amount of memory issues you experience in your code, you'll probably still miss a few due to exceptional situations and common mistakes.  Thankfully, the iOS SDK includes several tools to help you identify the over and under releasing of objects.  In Xcode you can use the "Analyze" build option to see if it detects any memory errors.  Also, Instruments provides a "Leaks" template (identifies under releasing) and a "Zombies" template (identifies over releasing).  I'll explore these tools in a future post!

Find Us
Contact Us 651-288-7000 1-800-866-9884
Home | Training | Curriculum | Course Finder | Schedule | Enroll | Twin Cities Java User Group | Consulting | Foundation | Jobs | About Us | Our Story | Press Room | Instructors | President | Map & Directions | Sitemap

Java Training | JSF / Struts / Spring / Hibernate Training | Java Power Tools Training | .NET 4.0 & Visual Studio 2010 Training | Microsoft Web Development Training | Prism / MVVM / MEF Training | .NET 3.5 and Visual Studio 2008 Training | .NET 2.0 and Visual Studio 2003 Training | Cloud Computing Training | Ajax / Web Services / XML Training | Groovy and Grails Training | SQL Server 2012 Training | SQL Server 2008 Training | SQL Server 2005 Training | Mobile Development Training | SharePoint 2010 Training | SharePoint 2007 Training | Agile, Process, Analysis & Design Training | Arch/Design Patterns Training | Microsoft Official Curriculum Training | Web Development Training | Ruby Training | Rational Application Developer (RAD) Training | WebSphere Application Server Training | WebSphere Portal Training | WebLogic Training | Boot Camp Training | Project Management Training | C / C++ Training | Metro / WinRT / Windows 8 Development Training | Retired

Intertech delivers training on-site and virtually serving cities including Phoenix, AZ | San Francisco, CA | Los Angeles, CA | San Diego, CA | San Jose, CA | Washington, DC | Chicago, IL | Orlando, FL | Boston, MA | Duluth, MN | Minneapolis St. Paul, MN | Rochester, MN | Raleigh-Durham, NC | New York, NY | Philadelphia, PA | Austin, TX | Dallas, TX | Houston, TX | Seattle, WA.