Monday, September 29, 2014

Starting From Scratch: Android - Action Bar

This week we're continuing the Starting From Scratch series. Today we're going to take a look at the Action Bar. The action bar UI was first defined in Android 3.x (API 11+). It provided a consistent navigation paradigm for applications as well as a convenient way to present context specific calls to action (like sharing, search, and etc).

Because Android only supported the Action Bar APIs on Android 11+ an open source project called ActionBarSherlock provided support for earlier versions of Android.  ActionBarSherlock is a great project and very useful and eventually Android added a similar Appcompat project to it's v7 support library. While I'm a big fan of ActionBarSherlock I'm going to be using Android's Appcompat project in my example code for consistency.

Creating a project that has an Action Bar.


Setup the support appcompat project as a library. Note, for purposes of this series i'm using android-14 as my target version. You'll want this to match whatever Android version your app is targeting.
$ cd /path/to/android-sdk/extras/android/support/v7/appcompat
$ android update project -p . -t android-14
Make sure that the project.properties file has the android library project property set.
android.library=true
Now that we have our pre-requisites complete let's create an app that will use an Action Bar.
$ cd ~
$ mkdir MyActionBarProject
$ cd MyActionBarProject
$ cp /path/to/android-sdk/extras/android/support/v4/android-support-v4.jar libs/
$ android create project -t android-14 -k com.example. myactionbarproject -p . -n MyActionBarProject -a MainActivity
In order to actually use the support library you need to add a reference to the Android Support Appcompat Library in your project.properties. Note that the path is relative NOT absolute.
android.library.reference.1=relative/path/to/android-sdk/extras/android/support/v7/appcompat
At this point you've got your application setup so that it can use an Action Bar, but it's not using one yet. In order to actually use an Action Bar you'll need to update your Android manifest to use a theme with an Action Bar. This can be done by using either Theme.AppCompat.Light or Theme.AppCompat (dark theme) as the theme of your activity in your AndroidManifest.xml. For example:
<activity android:name="MainActivity"
               android:label="@string/app_name"
               android:theme="@style/Theme.AppCompat.Light">
You'll also want to hint Android that you're going to support an older version of Android. You can do that by adding the following in your AndroidManifest.xml
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
At this point you can compile your app and install it on your test device or emulator and you'll see an Action Bar. Make sure you either have an emulator running or a device attached in debug mode and run:
$ ant clean && ant debug && ant installd

Action Bar Menu


One of the great things about the Action Bar is that you can provide menu items directly in the action bar. This allows you to provide context specific menu options in a place that is convenient and easy for your users to access.

If you are planning on supporting the Action Bar via the Support Library then the first thing to do is to update your Activity to extend ActionBarActivity instead of Activity.

Android provides an Action Bar Icon Pack which you can download and use in your application. Simply copy the resources from the theme your app is using into your res/drawable folders. For this example we'll use the refresh icon.

$ mkdir ./res/drawable-xxhdpi
$ cp /path/to/icons/holo_light/01_core_refresh/drawable-xxhdpi/ic_action_refresh.png ./res/drawable-xxhdpi/
$ cp /path/to/icons/holo_light/01_core_refresh/drawable-xhdpi/ic_action_refresh.png ./res/drawable-xhdpi/
$ cp /path/to/icons/holo_light/01_core_refresh/drawable-hdpi/ic_action_refresh.png ./res/drawable-hdpi/
$ cp /path/to/icons/holo_light/01_core_refresh/drawable-mdpi/ic_action_refresh.png ./res/drawable-mdpi/

The first thing you need to do to add a menu in your Action Bar is to define the menu layout. In my layout I'll be referencing an icon. Here's what our main_activity_menu.xml looks like.

$ mkdir res/menu
$ vim res/menu/main_activity_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:myapp="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/menu_refresh"
              android:icon="@drawable/ic_action_refresh"
              android:showAsAction="ifRoom"
              myapp:showAsAction="ifRoom" />
</menu>

Now that we've defined the Action Bar menu we need to inflate it into our Action Bar. This is done via the Activity's onCreateOptionsMenu event.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_activity_menu, menu);
              return super.onCreateOptionsMenu(menu);
          }

When a user selects a menu item the onOptionsItemSelected method will be called. This method is called regardless of which Menu Item was selected. So you'll need to check the id of the item before you handle the action. Here's an example of handling our refresh action.
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if(item.getItemId() == R.id.menu_refresh) {
        Toast.makeText(this, "Refresh selected", Toast.LENGTH_LONG).show();
        return true;
    }

    return super.onOptionsItemSelected(item);
}
At this point you can compile your app and install it on your test device or emulator and you'll see an Action Bar with a refresh menu button. Selecting the refresh button will display message saying Refresh select.
$ ant clean && ant debug && ant installd

Monday, September 22, 2014

Starting From Scratch: Android - Fragments

This week we're continuing the Starting From Scratch series. Today we're going to take a look at Android Fragments. I'll discuss what a Fragment is, the Fragment life-cycle, creating a Fragments options menu, and finally I'll give a few Fragment tips I've found along the way.

What Is A Fragment

Simply put, a Fragment is a way to encapsulate a piece of your applications UI and UI interactions into a reusable set of resources and code. A Fragment is not tied to any particular Activity, but instead can be used within many Activities.

One example of where I've used this modularity in my applications is with Lists. Lists are common in mobile applications and often only differ by what they show. Using Fragments it would be easy to encapsulate creating, displaying, and interaction with a list into a set of reusable code and resources. You could then display multiple lists in a variety of places throughout your app using the same code and resources.

Fragment Life-cycle

The Fragment life-cycle is very similar to the Activity life-cycle we've already gone through in this series. You still have creating, starting, resuming, pausing, stopping, and destroying life-cycle events. But in addition to those you have life-cycle events that are associated with creating your Fragments view and attaching/detaching from an Activity. I'm not going to go through every Fragment life-cycle method but instead will call out two key life-cycle differences from Activities.

The first big difference is in creating the Fragments view. In an Activity this is done via the onCreate method. In a Fragment this is done in the onCreateView method. The onCreateView method is expected to return the view to use with this Fragment. Creating this view is pretty simple, just inflate your Fragments layout using the LayoutInflator passes into this method.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    return inflater.inflate(R.layout.my_first_fragment_layout, container, false);
}

The next difference comes with the onActivityCreated method. The main purpose of this method is to allow the Fragment to restore state. There are two places that state can be stored. The first is internally within the Fragment via a Bundle. The second is in any arguments that were passed into the Fragment by it's composing Activity.

The internal saved state is passed into the onActivityCreated method in the form of a Bundle. The state that was passed in via arguments can be retrieved via a call to the getArguments method. It's important to restore Fragment state using the correct source of information. For instance, if you get the initial state from the Arguments but then update that state and save it in your Fragments Bundle then it's important to have some logic that determines the correct place to get the saved state from.

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
    super.onActivityCreated(savedInstanceState);
    Bundle arguments = this.getArguments();
    if(arguments != null && arguments.size() > 0)
    {
        // set any state that was passed in
        // via the arguements bundle
        this.someVariable = arguments.getString("SomeVariable");
    }
}

Creating Fragments Options Menu

Creating menu items for your Fragment is a four step process. The fist step is declaring your Fragments options menu in an XML file. The second step is declaring that your Fragment has an options menu. The third step is inflating your options menu layout. The last step is handling users selecting an option in your Fragments menu.

First, create res/menu/my_first_fragment_menu.xml. The important thing to call out here is that each menu item needs to have an id. This id is important because there is one method that is called when the user selects a menu item. So we need a way to differentiate the desired action the user wishes to perform.

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/my_menu_item" android:showAsAction="ifRoom"/>
</menu>

Declaring that your Fragment has an options menu is done via a call to setHasOptionsMenu. This call should be made in the Fragments default constructor.

public MyFirstAndroidFragment()
{
    setHasOptionsMenu(true);
}

Inflating your Fragments options menu is done by overriding the onCreateOptionsMenu method. This is done by passing the MenuInflater's inflate method the id of the menu XML file you created. If you want to use an ActionProvider in your Fragment, like the ShareActionProvider, this is the right time to set that provider up.

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
    inflater.inflate(R.menu.my_first_fragment_menu, menu);
    // this is a good time to setup a share action provider
}

Finally, handling the selection of a menu option is done by overriding the onOptionsItemSelected method. This method is called when any menu item is selected. It's a good idea to encapsulate the menu item action into it's own method and just call that method when the item has been selected. It's important to remember to return true in the onOptionsItemSelected method if you did handle the menu item selection.

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    if (item.getItemId() == R.id.my_menu_item)
    {
        this.handleMyMenuItem();
        return true;
    }
    return false;
}

Fragment Tips

Retaining

One thing that often causes people to stumble is putting a video, web browser, or any other stateful object inside a Fragment. The reason is that when the device changes orientation the Activity (and it's child Fragments) are torn down and recreated. This causes problems when the user isn't expecting it. One way to solve this problem is to tell Android to retain the Fragment instance across Activity re-creation. This is done via a call to setRetainInstance. This call should be made in the Fragments default constructor.

public MyFirstAndroidFragment()
{
    setRetainInstance(true);
}

Cross Fragment Coordination

Cross Fragment coordination is done by declaring an interface in your Fragment for any events you want to allow others Fragments to respond to. The Activities that compose your fragment will implement your Fragments interface and can then dispatch messages to other Fragments that it is composing. This allows you to keep your concerns separated correctly by NOT tightly coupling your Fragment with any other Fragment. It's okay to tightly couple your Activity with your Fragment because your Activity is composing that Fragment.

Monday, September 15, 2014

Starting From Scratch: Android - Activities


This week we're continuing the Starting From Scratch series. Today we're going to take a look at Android Activities. I'll discuss what an Activity is, how you create one, the Activity life-cycle, launching an Activity programmatically, and finally I'll give a few Activity tips I've found along the way.

What Is An Activity


According to the Android documentation, an Activity is "... a single, focused thing that the user can do." Yeah, that's pretty vague. So let's break it down.

In the early days of Android (pre-tablet) an Activity represented pretty much everything on the screen, how it got there, and how you interact with it. Basically the Activity was analogous to a "screen" in an application. If you wanted to display a different screen you either had to dynamically tear down the current screen and rebuild the new screen (very laborious) or, preferably, start a new Activity which owned the UI and interactions for the new screen. This allowed developers to encapsulate the concepts within a screen pretty nicely and manage workflow easier.

As Android matured, and tablets became mainstream, it became necessary to reuse portions of an Activity within other Activities. Thus was born the Fragment (which I'll talk about later in this series). Prior to Fragments a typical application would have many Activities. Once Fragments were introduced the number of Activities an application had were reduced from one per screen to one per workflow.

Creating an Activity


There are two steps necessary when creating an Activity. The first is to write the Java class which extends the Activity class. This class should implement any necessary life-cycle events (which are outlined below). The second step is to declare the Activity in the Android manifest. You can see an example of this by looking at the initial Activity that was created for your application in your AndroidManifest.xml.

Activity Life-cycle


An Activity has several states that it can be in. Those states are associated with creating, starting, resuming, pausing, stopping, or destroying the Activity.

Creating


When an Activity if first being created a call will be made to the Activities onCreate method. The onCreate method is responsible for associating a UI layout with the Activity. This is done via a call to the setContentView method with the associated layout ID. As mentioned previously in this series, a layout is a composition of the UI elements to display on screen.

For Example:
@Override 
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}

If you have any state that needs to be restored before the official call to onRestoreInstanceState you can do it after the call to setContentView using the saved instance state Bundle passed in. The typical reasons you may want state restored here is if you want to be able to make any decisions on the other life-cycle methods based on the current state of the Activity. Because of this, the onCreate method is passed a Bundle which will contain any state that was saved when the Activity was paused.

You cannot assume that the Bundle passed in to the onCreate method will exist. In the case that there is no previous state or if it's the first time the Activity is run the Bundle will be null. Therefore it is very important to check to make sure the Bundle exists before you try to use it. If the Bundle exists you can use the information you've saved in it to restore the internal state of the Activity.

NOTE: It is really important to draw the distinction here between resetting the internal state of an Activity and resetting the UI of an Activity. YOU SHOULD NOT try to interact with the UI in the onCreate method. The onCreate method is called when the Activity is starting but before it is displayed on the screen. If you try to get a handle to UI elements they will not exist.


Restarting


The onCreate method is only called when the Activity is not already in memory. Often it is the case that the Activity has been paused but not cleared out of memory. In this case when the Activity is about to be re-started the onRestart method is called. For most people there really isn't anything you need to do in onRestart. The internal state of your Activity will be the same as when it was paused, so there is nothing to really restore. The exception being if you are using a Cursor.

@Override 
public void onRestart() {
}

Starting


The onStart method is called after either onCreate or onRestart when the Activity is visible to the user. The Activity UI is not yet ready to be interacted with. At this point you still don't want to do anything programmatically with UI elements but you are able to reset internal Activity data.

@Override 
public void onStart() {
}

Resuming


Finally, we're at the point in the Activity life-cycle where you can do something with the UI. The onResume method is called right after the Activity has been displayed on the screen. At this point the UI is ready to be interacted with. If you did not register your UI event listeners in the layout file this is where you would want to register those listeners.
@Override 
public void onResume() {
}


At this point in the life-cycle your Activity is considered to be running.

Pausing


When your Activity is about to go into the background, but it is still active, the onPause method is called. This happens when another Activity is about to be put on top of your Activity (while it's still running) or your Activity is about to be put into the background or killed.
@Override 
public void onPause() {
}

This is a good time to commit changes to data and unwire any listeners that you've set up. It's important to note that onPause doesn't necessarily mean that your Activity is going into the background. This will also be called when a dialog is displayed on top of your Activity. In this case the next life-cycle event will be onResume instead of onStop.

It's important that this method returns very quickly as the onResume method for the Activity about to show will not get called until this method returns.

Stopping


The onStop method is called when another Activity has come to the foreground and fills the entire screen. On stop cause be used to save state as well as stop things that are time intensive.
@Override 
public void onStop() {
}

Destroying


The onDestroy method is called right before your Activity is about to be removed from memory. This is a good time to clean up the internal handles that your Activity may have.
@Override 
public void onDestroy() {
}

Saving State


In the previous life-cycle events I mentioned saving/restoring Activity state several times. Users will expect an Activity to be in the same state that they left it in. The user can leave the Activity for a variety of reasons like to answer a phone call or to use another app. Sometimes when a user has a lot of applications running or is doing something very memory intensive Android needs to completely remove the Activity from memory when it's not on the screen. In that case displaying the Activity again will cause it to re-display as if it was never on the screen to begin with. This is why it is important to make sure you restore the internal Activity state if there is any to restore

Saving state is done via the onSaveInstanceState method. Restoring state is done via the onRestoreInstanceState method. The onSaveInstanceState method is called before the Activity is killed. If onSaveInstanceState is called, it will be called before the onStop life-cycle event is called. The onSaveInstanceState is passed a Bundle which should be used to save instance state too. That bundle will then be passed back to the onCreate life-cycle event.

onRestoreInstanceState is called after onStart and is used to restore any state saved in the call to onSaveInstanceState. For example:
@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString("SomeVariable", someVariable);
@Override
public void onRestoreInstanceState(Bundle savedState) {
    if(savedState != null) {
        this.someVariable = savedState.getString("SomeVariable");
    }
}

Launching an Activity


There are two main ways to launch an Activity. The first way is to specify the type of action you want performed and allowing the user to select the appropriate application they want to handle that. This is commonly used when sharing data or launching a url.
private void openUrlInBrowser(String url) {
    Uri uri = Uri.parse(url);
    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    this.startActivity(intent);
}

The second way to launch an Activity is by class name. This is the case when you want to launch a very specific Activity. Typically this is how you would launch another Activity within your application.

private void openSomeOtherActivity() {
    Intent intent = new Intent(this, SomeOtherActivity.class);
    this.startActivity(intent);
}

In either case launching an Activity is a two step process. The first step is to create an Intent which details what you want to do. You decide how you want to launch the Activity based on the Intent constructor you select. The second step is to call the startActivity method from your Activity.


Activity Tips



  • Only restore an Activities internal state in onCreate. Never try to restore UI.
  • The first time an Activity is being displayed, the Bundle passed into onCreate will be null.
  • Reset an Activities UI in onResume.
  • Don't change the name of the Activity used to start the application. Changing that will cause the any home screen icons associated with the previous Activity to be broken after the application is updated. The is because the icons are associated with the previous Activity name.



Monday, September 8, 2014

Starting From Scratch: Android - Resources

This week we're continuing the Starting From Scratch series. Today we're going to take a look at Android resources. There are many types of resources in Android. First i'm going to outline the different resource types. Then I'll explain what configuration qualifiers are and what they're used for. Finally I'll call out a few important configuration qualifiers that will be used in most applications.

All resources in your Android application are stored in the res/ folder of your project. Resources are grouped by type and configuration.

Resource Types


The easiest way to explain the different resource types is to simply list out the folder structure and what type of resource is provided in each folder. The following is a list of the various resource types.

res/
anim/Store tween animation XML files in this directory.
color/Store color XML files in this directory.
drawable/Store bitmaps (png, jpg, gif) files, or XML files for bitmapsframe animations, 9 patches, state lists, and shapes in this directory.
layout/Store layout XML files (UI composition) in this directory.
menu/Store menu XML files in this directory.
values/Store XML files for strings, styles, other value types in this directory.

Configuration Qualifiers


One of the most powerful things that you can do with Android resources is specify configuration qualifiers for the various resource types. Configuration qualifiers allow you to target specific resources towards a specific device, screen size, or etc. There are different configuration qualifiers depending on the context in which they are used.

Configuration qualifiers are appended to the resource type and separated with a dash (<resource type>-<configuration qualifier>). I won't go into detail on each qualifier as table 2 in the Android resource documentation provides an exhaustive list of all qualifiers. But I want to call out a few different qualifiers that are important to know.

Screen Pixel Density


Screen pixel density qualifiers are used with drawables and help you to avoid images that look terrible from being scaled up as well as providing lower resolution images for screens that are not very dense.  There are six types of screen pixel densities nodpi, tvdpi, ldpi, mdpi, hdpi, and xhdpi.

nodpi is for resources that you do not want scaled. tvdpi is for screens that fall in-between mdpi and hdpi (like televisions). ldpimdpihdpi, and xhdpi are for low, medium, high, and extra high density screens respectively.

For example, images in the res/drawable-mdpi/ folder should be images that are ideal on a medium density screen.

If a screen pixel density is not specified that's ideal for the device Android will scale up/down based on the best match density.

Language and Region


Language and region qualifiers use the ISO 639-1 language and an optional ISO 3166-1-alpha-2 region preceeded by a lowercase r. For example fr-rCA for Canadian French. Language and region qualifiers are the easiest way to localize your application and provide different text translations for different languages and regions.

Screen Size


Screen size qualifiers allow you to target screens using small, normal, large, and xlarge. When targeting Android versions prior to Honeycomb these are best way to provide layouts optimized to specific screen sizes. But, it's important to note that the screen size qualifier is not the ideal way to determine phone versus tablet. There are some tablets with lower screen sizes than some of the higher end phones. This is because the size relates to the density of the screen.

If you're providing an application that supports a version of Android prior to Honeycomb and you want to target screen size you should use a combination of screen size and the smallest width qualifier.

Smallest Width


The smallest width qualifier allows you to specify screen sizes with a minimum number of density independent pixels. The format us sw<N>dp. For example layout-sw600dp provides a layout for screens with a minimum of 600 density independent pixels.


In Oct 2013 I gave a presentation at the Big Android BBQ on Building For Multiple Screens. If you're interested in a deeper dive into the subject checkout my presentation slides.

Monday, September 1, 2014

Starting From Scratch: Android - Creating Your Project

This week I'd like to start a new series called Starting From Scratch. The idea behind the Starting From Scratch series is to give you real world insight into a specific topic. According to PC World, Android currently makes up 84% of the overall smartphone market. So I thought a good place to start the Starting From Scratch series would be with Android.

If you've been following this blog for a while, you know that I'm not a fan of the traditional IDE. Given that, I won't be using Eclipse for this series. I'm going to walk you through creating a project from the command line.

Installing the Android SDK Tools

The first thing you need in getting started with Android development is to download the SDK. Head over to the Android developer site and download the SDK tools (you don't need the ADT plugin for this series). The second thing you need to do extract the SDK tools and, for convenience, add them to your path.

On *nix, for the latest version to date, this can be accomplished by running:
$ cd ~/
$ curl http://dl.google.com/android/android-sdk_r23.0.2-linux.tgz | tar -xzvf -
$ echo 'export PATH="$PATH:~/android-sdk-linux/tools:android-sdk-linux/platform-tools"' >> ~/.bash_profile
$ . ~/.bash_profile
Installing the Android SDK

Installing the SDK tools doesn't actually install any of the SDKs. The next thing we need to do is install one or more of the Android SDK versions. Which SDK versions you install depends on your applications target audience. You should take a look at the Android Platform Versions website to see what versions you should install. For this tutorial we're going to install the platform tools and Android 4.4.2.
$ android update sdk --no-ui -t tool,platform-tool,19
Creating a project

The android tool that comes with the Android SDK allows you to create projects from the command line. There are several things that you need to provide the tool when creating the project. These are:

  • Android version
  • Package name
  • Path of the project
  • Name of the Application
  • Name of the main Activity

The Android version is the name of the Android version you want to target. You can get a list of all installed Android versions by running $ android list target.

The package name is the namespace to use within your project. This is typically your domain in reverse. For instance if your domain was www.foo.com your package name would be com.foo.

The path is the directory where the project files should be created under.

The name of the application is, well, the name of the application.

The name of the main Activity is the name of the Activity that will be launched when a user opens the application. I'll get into what an Activity is later in this series.
$ cd ~/
$ mkdir MyFirstAndroidApp
$ cd MyFirstAndroidApp
$ android create project -t android-19 -k com.example.myfirstandroidapp -p . -n MyFirstAndroidApp -a MyFirstAndroidActivity

Building The App

At this point you actually have an app that can be built and installed on a phone. You should follow these instructions and put your device in developer mode. Once you have your device ready you can plug it in and run:
$ ant debug && ant installd
The default Android command line build system is built on top of Apache Ant. Ant uses a build file which tells it how to to build a project. When you installed the Android SDK tools you got several Android specific Ant targets which have been created to allow compilation, signing, and other interactions with your application build artifacts. When you created the project using the android binary a build.xml file was created for you in your project directory. This is the Ant build file.

Running the command ant debug tells the Android build system to compile the application for debug. The ant installd command tells Ant to install the debug Android package (APK) on the connected device.