ActionBar

ActionBarCompat – Part 3

In the previous article we converted our resources for the code from the previous ActionBar series to use ActionBarCompat. In this article we’ll have a look at the Java code and begin looking at the changes that we need to make it backwardly compatible to API level 7 using ActionBarCompat.

The first thing that we need to remember when making the code backwardly compatible to API 7 is that there will be other classes and methods that we have used in our original code which itself is not compatible back to API 7. Specifically in the case of the ActionBar code we used Fragments, and we used the native implementations, so we’ll also need to change these to use the support library implementation of Fragment.

Let’s start simply by looking at com.stylingandroid.basicactionbar.Fragment1:

package com.stylingandroid.basicactionbar;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Fragment1 extends Fragment
{
	@Override
	public View onCreateView( LayoutInflater inflater,
		ViewGroup container,
		Bundle savedInstanceState )
	{
		return inflater.inflate(
			R.layout.frag1,
			container,
			false );
	}
}

We can see from line 3 that this imports the native Fragment support which is built in to API 11 and later, so it’s a really simple task to convert this by simply changing the include:

[java highlight='3']
package com.stylingandroid.basicactionbar;

import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Fragment1 extends Fragment
{
.
.
.

That’s easy enough, and the change to com.stylingandroid.basicactionbar.Fragment2 is identical, so I won’t bother covering that.

Converting com.stylingandroid.basicactionbar.MainActivity is a little tricker, but it’s much more complex class than the two we’ve already converted, so that’s to be expected. The first thing to look at is the includes and identify the classes that are not available in API 7. One trick for doing this is to change the build target API level to API 7 and the compiler will identify the classes and methods which aren’t available. We’ll go through them now.

package com.stylingandroid.basicactionbar;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.ActionBar;
import android.app.ActionBar.OnNavigationListener;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SimpleAdapter;
import android.widget.Spinner;
import android.widget.TextView;

The highlighted classes are not available, so we need to change them to the equivalents from the support Library:

package com.stylingandroid.basicactionbar;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.view.ActionMode;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SimpleAdapter;
import android.widget.Spinner;
import android.widget.TextView;

The next thing that we need to do is change the base class. When we use Fragments from the support library, we need to subclass FragmentActivity (or one of its siblings) instead of Activity because it provides part of the framework that the support library implementation of Fragments require. ActionBarCompat works in a similar way and requires us to subclass ActionBarActivity in any Activities where we require ActionBar support. ActionBarActivity itself subclasses FragmentActivity, so we get all of the support library Fragment framework as part of this:

public class MainActivity extends ActionBarActivity

The next thing that we must do is locate all calls to the getActionBar() method and replace them with getSupportActionBar(). The reason for this is that getActionBar() will exist on the class in its native form on API 11 and later, but won’t be available before then. ActionBarCompat will use the native ActionBar implementation if it is available and the back port if it is not, therefore it does not override the native getActionBar() method, ActionBarActivity provides getSupportActionBar() and we must always get a reference to the ActionBar using this method.

For example, here’s our onCreate() method:

@Override
public void onCreate( Bundle savedInstanceState )
{
	super.onCreate( savedInstanceState );

	int mode = ActionBar.NAVIGATION_MODE_TABS;

	if (savedInstanceState != null)
	{
		mode = savedInstanceState.getInt( "mode",
			ActionBar.NAVIGATION_MODE_TABS );
	}
	ActionBar ab = getActionBar();
	ab.setDisplayShowTitleEnabled( false );
	if (mode == ActionBar.NAVIGATION_MODE_TABS)
	{
		setTabNavigation( ab );
	} else {
		setListNavigation( ab );
	}
}

Which we must change to:

@Override
public void onCreate( Bundle savedInstanceState )
{
	super.onCreate( savedInstanceState );

	int mode = ActionBar.NAVIGATION_MODE_TABS;

	if (savedInstanceState != null)
	{
		mode = savedInstanceState.getInt( "mode",
			ActionBar.NAVIGATION_MODE_TABS );
	}
	ActionBar ab = getSupportActionBar();
	ab.setDisplayShowTitleEnabled( false );
	if (mode == ActionBar.NAVIGATION_MODE_TABS)
	{
		setTabNavigation( ab );
	} else {
		setListNavigation( ab );
	}
}

We need to do the same thing for Fragments and replace calls to getFragmentManager() with getSupportFragmentManager().

In the next article we’ll complete the code changes necessary for our switch to ActionBarCompat.

The full source code for this article will be published along with the next article, once we have the code completed.

© 2013 – 2014, Mark Allison. All rights reserved.

Copyright © 2013 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.