Is it just me, or are Android tabs a real headache? There are tabs that host activities, tabs that host views, tab widgets, tab content providers, and now (apparently), Android developers have to worry about something called fragments. I’m a big fan of Android, but I’m not thrilled with a lot of the UI framework, and tabs are the worst offenders.

And yet there are times, when I can’t make do with anything other than Android tabs. During those times, I grab a cup of coffee, pull up the Google code docs, and try out of respect for my coworkers to keep my cursing to a minimum. The last time I had to implement a tabbed UI, I decided what was really needed was a bare bones sample program. Something so minimalistic that regardless of how convoluted the tab layout hierarchy is one couldn’t help but get it right.

My project had a deadline quickly approaching, and as has always proved the case for me, implementing my tabbed UI ate up more time than I’d allocated, so I shelved the tab tutorial for a rainy day. Fast forward several months to when a TechRepublic reader emailed me about doing a tab tutorial, and I thought it was a perfect time for me to dig into Android tabs and slay this dragon once and for all.

However, when I pulled up those same Google code docs I referenced previously, I was greeted by a big bold note informing me the TabActivity class had been deprecated. My initial reaction was one of utter exuberance. I assumed at last the Google UI framework team had gone back and pulled this thorn from my side.

I quickly discovered that the new recommended class for handling tabs is vastly more complicated than its predecessor (though it is more flexible, especially when it comes to tablets). In fact, the new mechanism is so much more involved that it requires users download a compatibility library into their development environment, and utilize a static inner class, which includes the following comment:

This is a helper class that implements a generic mechanism for associating fragments with the tabs in a tab host.  It relies on a trick.

That’s right. The official way of doing tabs now relies on “a trick.” While there was an awkward period during my youth where I dreamed of being a magician, I gave up that career path about the time I discovered the pretty girl who lived two houses down from me preferred a boy on the soccer team to one who could produce 12 feet of knotted silk from a previously empty cardboard box.

So after doing a good bit of soul searching (about this tutorial not about becoming a magician), I decided to go ahead and demonstrate the “old” way of doing tabs. For those of you who say shame on me, I offer the following arguments:

  • While the FragmentActivity works, it is simply too complex an implementation to cover in a single TechRepublic post.
  • The tutorials I write for TechRepublic are aimed at beginners, and the FragmentsTabs sample provided by Google could send developers not familiar with the workings of the now deprecated TabActivity running for cover (or worse, an iPhone).
  • The “new” way of doing tabs is targeted at devices running Honeycomb and above, which according to Google’s own dashboard accounts for less than 1.5% of the market.

I’m not saying don’t bother to learn how to use the Fragment classes — if you want to develop for Android, eventually you will not have a choice — I’m saying that learning how the deprecated TabActivities work will get you up and running faster. Another advantage to learning the “old” way is that you’ll gain knowledge you’ll be able to use when you move on to the new way of doing things. (Right now, a lot of what is handled automatically for the developer using the TabActivity class has reverted back to manual handling in the FragmentActivity class.)

This tutorial can get your tabs up and running quickly on 98.5 % of the devices people have today; it will give you the background you’ll need to code something that works for the other 1.5% of potential users; and, ice cream sandwich is just around the corner, and some improvements are likely forthcoming in this area.

You can work through the tutorial that follows, or download the project here.

Go to page two to see the tutorial.

1.       Create a new Android project targeted at SDK 1.6 or above.

2.       In the /res/layout folder create an XML layout for the main activity.

main.xml
<?xml version="1.0" encoding="utf-8"?>
<TabHost
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@android:id/tabhost"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TabWidget
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:id="@android:id/tabs"/>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="0"
android:id="@android:id/tabcontent"/>
</LinearLayout>
</TabHost>

3.       You will need a simplistic layout for both of the activities our tab activity will host; both of these activities go in the /res/layout folder.

activity_1.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:background="#ff0000">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="26sp"
android:textStyle="bold"
android:textColor="#ffffff"
android:text="This is one activity."/>
</LinearLayout>
activity_2.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:background="#0000ff">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="26sp"
android:textColor="#ffffff"
android:text="And this is another."/>
</LinearLayout>

4.       Add two lines to the generated AndroidManifest.xml file — one for each of the activities the tab widget will host. These activities get defined in the application node of the manifest as shown below.

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.authorwjf"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Main"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".FirstActivity" />
<activity android:name=".SecondActivity" />
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>

5.       In your /src folder, you should create two new classes that correspond to the two classes we added to the manifest.

FirstActivity.java
package com.authorwjf;
import android.app.Activity;
import android.os.Bundle;
public class FirstActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_1);
}
}
SecondActivity.java
package com.authorwjf;
import android.app.Activity;
import android.os.Bundle;
public class SecondActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_2);
}
}

6.       Implement the Main.java class. In the class, you create a new tab host, and then create tab specs for each tab and its corresponding activity. Those tab specs are added to the tab host.

Main.java
package com.authorwjf;
import android.app.TabActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
public class Main extends TabActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TabHost th = (TabHost)findViewById(android.R.id.tabhost);
TabSpec ts1 = th.newTabSpec("tab_id_1");
TabSpec ts2 = th.newTabSpec("tab_id_2");
ts1.setIndicator("First Tab").setContent(new Intent(this,FirstActivity.class));
ts2.setIndicator("Second Tab").setContent(new Intent(this,SecondActivity.class));
th.addTab(ts1);
th.addTab(ts2);
}
}

When you run the app, you’ll find it’s not very impressive (Figure A and Figure B). That’s okay because it was meant to be clear and easy to digest. I hope in that regard you’ll agree this tutorial is a success.
Figure A

Figure B

For those of you who still question my decision not to write this Android tutorial around the newer fragment classes…keep your shorts on. I didn’t say I’d never write a TechRepublic tutorial on the topic — I just prefer to eat my Android pie in small bites. Bon appétit!