How to migrate the android menu button to the action bar

Today I would like to describe how to migrate the android menu button, on devices with release older than 3.0, to the action bar using the Android Support Libraries. The menu button is well known on devices which were shipped with Android release 2.3.x and older and has been deprecated in newer releases. Actually devices which were shipped with newer releases than 2.3.x usually don’t have a hardware button which is related to the options menu. Although it is possible to emulate the hardware button using backward compatibility, it is recommended to migrate to the action bar instead.

How to create an options menu in releases before 3.0

At first let’s resume how to create an options menu in releases before honeycomb. You need to override at least the methods onCreateOptionsMenu(Menu) and onOptionsItenSelected(MenuItem) in the related activity where the options menu should appear. The activity is extended from class android.app.Activity.

In the activity we override the method onCreateOptionsMenu(Menu) where we describe how the menu should be built in the following manner.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
   getMenuInflater().inflate(R.menu.option_menu, menu);
return super.onCreateOptionsMenu(menu);
}

The structure of the menu is described in the menu xml (in our example option_menu.xml)

The system will call the method onOptionItemSelected(MenuItem) whenever a menu item will be selected. We can override that method to describe the reaction on that event.

@Override
public boolean onOptionsItemSelected(MenuItem item) {

   switch(item.getItemId())
   {
      case R.id.option1:
      break;

      case R.id.option2:
      break;
   }

return super.onOptionsItemSelected(item);
}

The option_menu.xml is where we describe the structure of the options menu. In our example we want to define 2 options which should appear in the menu.

file res/menu/option_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >    
   <item
      android:id="@+id/option1"
      android:title="@string/option1"/>
        
   <item
      android:id="@+id/option2"
      android:title="@string/option2"/>
</menu>

The related strings.xml for the text

<resources>
    <string name="app_name">Noactionbar</string>
    <string name="option1">First Option</string>
    <string name="option2">Second option</string>
</resources>

Steps to migrate to the ActionBar

Add support-library to the project

To migrate now this structure to the action bar we need to add at first the support library support-v7-appcompat.jar to our project. Support libraries are used to make objects usable on devices running Android releases where these objects were not implemented. Our Action bar is one of those objects we would like to make accessible in older releases as well. How to add the support library is described in the Android documentation. http://developer.android.com/tools/support-library/setup.html.

As this library includes resource items we have to apply it as a library project, to ensure to be able to access all resource items implemented in that support library.

Be sure to have the same or newer API configured as build target in your project properties to have all resources of the support library available in your project as well.

If you omit this part you will get disgusting error messages similar to this:

...\extras\android\support\v7\appcompat\res\values-v14\styles_base.xml:100:
error: Error retrieving parent for item: No resource found that matches 
the given name 'android:TextAppearance.Holo.Widget.ActionBar.Subtitle.Inverse'.

Assuming the build target of the support library is level 16 the project properties of our project should look like shown in the figure.

project_properties

Use ActionBarActivity from the support library

Afterwards we have to extend android.support.v7.app.ActionBarActivity instead of android.app.Activity for our activity class which should use the Action Bar. Ensure to have the correct Activity class imported as shown in the below code snippet.

//import android.app.Activity;
import android.support.v7.app.ActionBarActivity;

//public class MainActivity extends Activity {
public class MainActivity extends ActionBarActivity {

Add custom namespace in menu description file

As we want to use xml attributes in our menu description which in older releases are not existent, we have to create a custom namespace to be able to adress those attributes.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:withactionbar="http://schemas.android.com/apk/res-auto">

To use now the mentioned attributes we have to prefix them with the defined custom namespace. For example the attribute showAsAction which is available to ensure how menu items will be displayed in the action bar.

<item
   android:id="@+id/option1"
   android:title="@string/option1"
   withactionbar:showAsAction="never"
/>

The value ’never‘ states that we want the menu item to be never displayed in the action bar but in the overflow menu which will replace our options menu well known in releases before honeycomb.

Add the ActionBar Theme to the Manifest

The ActionBar theme which will be used for the activity using the action bar item from the support library, has to be defined in the Android Manifest. This will be done with the additional line android:theme … as shown below.

<activity
   android:theme="@style/Theme.AppCompat.Light" 
   android:name="de.bitcook.withactionbar.MainActivity"
   android:label="WithActionBar">
   <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
</activity>

If you omit this part you may get the following error message as a result:

java.lang.RuntimeException: Unable to start activity 
ComponentInfo{de.bitcook.withactionbar/de.bitcook.withactionbar.MainActivity}: 
java.lang.IllegalStateException: You need to use a Theme.AppCompat theme 
(or descendant) with this activity.

This is due to the fact that we are using the activity based on the support library resources which includes in this case the theme resources. The theme used for the activity should be derived from Theme.AppCompat when using the support library.

As an option you can change the theme for the whole application. This theme will be applied for all activities within the application, assuming of course that all activities are based on the support library.

<application
   android:allowBackup="true"
   android:icon="@drawable/ic_launcher"
   android:label="@string/app_name"
   android:theme="@style/Theme.AppCompat.Light">
   <activity
      android:name="de.bitcook.withactionbar.MainActivity"
      android:label="WithActionBar">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
         <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
   </activity>
</application>

Result and further details

After implementing those small changes to the application you will get the actionbar visible on all devices within the defined API level range in the Android Manifest beginning with API level 7 as shown in the figure.

actionbar_rel4.2.2

You will probably find out that the overflow button in the action bar is missing on devices running release 2.3.x or older, but shown in newer releases using the virtual devices of the SDK (AVD). In this case the application will still use the hardware buttons to show the menu. This is due to the fact that these devices usually have the hardware button for the menu. Actually you will notice the same behaviour when running a newer release on devices which still have the hardware buttons present, but only when installing the application on real hardware. I wasn’t able to simulate this behaviour in AVD.

If the uses-sdk attribute in the Android Manifest is set to enforce the application to use the backward compatibility for the menu button, you will notice that the application will show the legacy button and the overflow button in the actionbar, when migrating to the actionbar. So be sure to set targetSdkVersion at least to 11.

When using the support library support-v7-appcompat.jar for the actionbar implementation you should also ensure to have minSdkVersion to 7 to support devices running release 2.1 and newer.

You will find the source files for this example in the download area. You can import the example in your eclipse by creating the project from existing source code. Be aware that you need the support library setup and related to your project.