Android TabActivity with two list views

Often times when creating an activity with tabs, it’s easy to have a separate activity for the tab content.  However, things get tricky when those activities need to interact with one another.

So the solution is to create a tabactivity with views (instead of activities) as the tab content.  We see a very simple example of this in the official Android tutorial Hello, TabWidget.

In this tutorial, we will create a slightly more advanced application.  We will have two listviews as the content of a tabactivity and have them interact with one another (basically by clicking the items of one list view will add them to the second list view).

Step 1: Create Layout

First we need to create a layout that features a TabHost, TabWidget, and our two List Views:

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

Step 2: Create Activity

Next, we will write the Java source for our TabActivity. First, we create an Activity that extends TabActivity. We want to get the tabhost from the tabactivity to add our two list views.

tabHost = getTabHost();

// setup list view 1
listView1 = (ListView) findViewById(R.id.list1);

// setup list view 2
listView2 = (ListView) findViewById(R.id.list2);

Next, we need to add the views to the tabhost by setting the content of each tab as an anonymous class of TabContentFactory.

// add views to tab host
tabHost.addTab(tabHost.newTabSpec(LIST1_TAB_TAG).setIndicator(LIST1_TAB_TAG).setContent(new TabContentFactory() {
	public View createTabContent(String arg0) {
		return listView1;
	}
}));
tabHost.addTab(tabHost.newTabSpec(LIST2_TAB_TAG).setIndicator(LIST2_TAB_TAG).setContent(new TabContentFactory() {
	public View createTabContent(String arg0) {
		return listView2;
	}
}));

Step 3: Customize

If you want to programmatically change the tab, you should call setCurrentTab(index) on the tabhost where index is the tab number.  If you want to add a listener to know when the user changes the tab, you need to add a OnTabChangeListener like this: tabHost.setOnTabChangedListener(this)

Full Source

The full source for this example is here:

/**
 * This activity allows you to have multiple views (in this case two {@link ListView}s)
 * in one tab activity.  The advantages over separate activities is that you can
 * maintain tab state much easier and you don't have to constantly re-create each tab
 * activity when the tab is selected.
 */
public class TabbedListListActivity extends TabActivity implements OnTabChangeListener {

	private static final String LIST1_TAB_TAG = "List1";
	private static final String LIST2_TAB_TAG = "List2";

	// The two views in our tabbed example
	private ListView listView1;
	private ListView listView2;

	private TabHost tabHost;

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

		tabHost = getTabHost();
		tabHost.setOnTabChangedListener(this);

		// setup list view 1
		listView1 = (ListView) findViewById(R.id.list1);

		// create some dummy strings to add to the list
		List<String> list1Strings = new ArrayList<String>();
		list1Strings.add("Item 1");
		list1Strings.add("Item 2");
		list1Strings.add("Item 3");
		list1Strings.add("Item 4");
		listView1.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, list1Strings));

		// setup list view 2
		listView2 = (ListView) findViewById(R.id.list2);

		// create some dummy strings to add to the list (make it empty initially)
		List<String> list2Strings = new ArrayList<String>();
		listView2.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, list2Strings));

		// add an onclicklistener to add an item from the first list to the second list
		listView1.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView parent, View view, int position, long id) {
				String item = (String) listView1.getAdapter().getItem(position);
				if(item != null) {
					((ArrayAdapter) listView2.getAdapter()).add(item);
					Toast.makeText(TabbedListListActivity.this, item + " added to list 2", Toast.LENGTH_SHORT).show();
				}
			}
		});

		// add views to tab host
		tabHost.addTab(tabHost.newTabSpec(LIST1_TAB_TAG).setIndicator(LIST1_TAB_TAG).setContent(new TabContentFactory() {
			public View createTabContent(String arg0) {
				return listView1;
			}
		}));
		tabHost.addTab(tabHost.newTabSpec(LIST2_TAB_TAG).setIndicator(LIST2_TAB_TAG).setContent(new TabContentFactory() {
			public View createTabContent(String arg0) {
				return listView2;
			}
		}));

    }

	/**
	 * Implement logic here when a tab is selected
	 */
	public void onTabChanged(String tabName) {
		if(tabName.equals(LIST2_TAB_TAG)) {
			//do something
		}
		else if(tabName.equals(LIST1_TAB_TAG)) {
			//do something
		}
	}
}

Now when you run this app, you will have a tab activity with two tabs (each list view). Clicking on one item in the first tab will add that item to the second tab.

More advanced tutorials with tabs to come, including a tab activity with a map view and list view and the interaction between them.

Check out Android Tabs with Map and List View Tutorial.

To see a mult-list tab activity in action, check out my “Draft Punk” Android app.

38 thoughts on “Android TabActivity with two list views

  1. Pingback: Android Tabs with interacting map and list views « Josh Thought

  2. wangpeng

    i used it ,but it give me mistaks
    09-15 12:34:26.751: ERROR/AndroidRuntime(1160): Uncaught handler: thread main exiting due to uncaught exception
    09-15 12:34:26.772: ERROR/AndroidRuntime(1160): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.test.TabbedListListActivity/com.test.TabbedListListActivity.TabbedListListActivity}: android.view.InflateException: Binary XML file line #2: Error inflating class tabhost
    09-15 12:34:26.772: ERROR/AndroidRuntime(1160): Caused by: android.view.InflateException: Binary XML file line #2: Error inflating class tabhost

    coule you give me your this sample code.

  3. Josh Post author

    The code block for the layout XML incorrectly was showing the tags as all lowercase. They should be upper camel case (ie TabHost instead of tabhost). I have since fixed the code block plugin, give a try, and let me know how it goes. Thanks for the report.

  4. wangpeng

    code 17 line is wrong which need to delete, you also need to
    tabHost.setCurrentTab(1);
    tabHost.setCurrentTab(0);

    but in your another tutorial ,setCurrentTab donot need which i add comment.

  5. Josh Post author

    You’re right about line 17 of the layout, the syntax highlighter auto-completed the TabHost tag later in the layout which is incorrect. It needs to be closed at that line, I have fixed the syntax highlighter again and the correct layout is updated.

  6. Randy

    Hi!

    I have some errors:
    -> listView1.setOnItemClickListener(new OnItemClickListener()…//Eclipse tells me the “setOnItemClickListener” arguments are wrong…(?)
    ->tabHost.addTab(tabHost.newTabSpec(LIST1_TAB_TAG).setIndicator(LIST1_TAB_TAG).setContent(new TabContentFactory() {…//Eclipse tells me the “setContent” arguments are wrong…(?)

    Thx for the Help! :)

    Randy

  7. Nick

    Thanks for this tutorial, i found it very helpful and finally helped me get tab’s working properly in an app.

  8. Paul

    Josh,

    This is the cleanest/least amount of code example I have found. I have tried several others.

    Thanks for posting!
    Paul.

  9. Erik

    Hi there,

    very nice tutorial, helped me a lot to understand layouts and tabbing. I just got one Problem: When I open the app both views (I got one ImageView and one ListView) are displayed simultanously on top of each other. When a change tabs everything goes to normal.

    Any idea?

  10. Dimitri

    Great tutorial!
    Really helpful delves a bit deeper than other tutorials which simply copy stuff from android-developers forum.

    I am trying to implementing a ViewFlipper that contains two views of TabHosts, but failing miserably .
    The reason for this is I want to flip between the two sets of tabs.
    Is there any case you can help by pointing out a possible solution….

    Thanks in advance for your time and effort,
    Dimitri

  11. Josh Post author

    @Erik – I’ve run into that before. There is an issue with your layout file. I can’t say what the issue is without seeing it. A workaround is to call setCurrentTab(0), then setCurrentTab(1) at the bottom of onCreate(). This will simulate you changing tabs and will fix your issue.

  12. Josh Post author

    @Dimitri – I don’t know off the top of my head and will have to think about it. It may be possible to swap tab hosts within the same activity, but that starts getting really complex. You may have to have two separate tab activities to swap between.

  13. Shaun

    Just wanted to say thanks for the great tutorial. Only issue I’m having, which could very well be something I’m not doing right, is that I can’t the contents of my tabs to actually display. I want to use a custom activity for each of the three I have and just seem to be doing something very wrong.

  14. Ian

    I got the code working had to make some mods, as follows:

    package com.TabList;

    import java.util.ArrayList;
    import java.util.List;
    import android.app.TabActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.AdapterView.OnItemClickListener;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    import android.widget.TabHost;
    import android.widget.TabHost.OnTabChangeListener;
    import android.widget.Toast;
    import android.widget.TabHost.TabContentFactory;

    //ListActivity
    public class TabList extends TabActivity implements OnTabChangeListener {
    private static final String LIST_TAB_TAG1 = “list1″;
    private static final String LIST_TAB_TAG2 = “list2″;
    // private static final String LIST_TAB_TAG = “List”;
    // The two views in our tabbed example
    private ListView listView1;
    private ListView listView2;
    private TabHost tabHost;
    @SuppressWarnings(“unchecked”)
    @Override

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    tabHost = getTabHost();
    tabHost.setOnTabChangedListener(this);
    // setup list view
    listView1 = (ListView) findViewById(R.id.list1);
    // create some dummy strings to add to the list

    List listStrings = new ArrayList();
    listStrings.add(“Item “);
    listStrings.add(“Item “);
    listStrings.add(“Item “);
    listStrings.add(“Item “);
    listView1.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, listStrings));
    // setup list view

    listView2 = (ListView) findViewById(R.id.list2);
    // create some dummy strings to add to the list (make it empty initially)
    // List listStrings = new ArrayList();
    listView2.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, listStrings));
    // add an onclicklistener to add an item from the first list to the second list
    listView1.setOnItemClickListener(new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View view, int position, long id) {
    String item = (String) listView1.getAdapter().getItem(position);
    if(item != null) {
    ((ArrayAdapter) listView1.getAdapter()).add(item);
    Toast.makeText(TabList.this, item + ” added to list “, Toast.LENGTH_SHORT).show();
    }
    }
    });

    // add views to tab host
    tabHost.addTab(tabHost.newTabSpec(LIST_TAB_TAG1).setIndicator(LIST_TAB_TAG1).setContent(new TabContentFactory() {
    public View createTabContent(String arg) {
    return listView1;
    }
    }));

    tabHost.addTab(tabHost.newTabSpec(LIST_TAB_TAG2).setIndicator(LIST_TAB_TAG2).setContent(new TabContentFactory() {
    public View createTabContent(String arg) {
    return listView2;
    }
    }));

    }

    /**

    * Implement logic here when a tab is selected

    */

    public void onTabChanged(String tabName) {
    if(tabName.equals(LIST_TAB_TAG1)) {
    //do something
    }
    else if(tabName.equals(LIST_TAB_TAG2)) {
    //do something
    }
    }

    }

    Good article though, very useful :-)

  15. Untouchab1e

    I have the same problem as Shaun. Initially, both lists show up in the first tab. If I switch tabs, then everything is how it should be.

    Cant figure out what causes it

  16. Untouchab1e

    Thanks. A solution to the issue would be wonderful though, preferably based on the code you posted here, as I reckon the fix for it should be fairly small. I just havent been able to figure it out myself yet :/

  17. adrolmar

    when I first run app listView1 shows its items and listView2′s items as well; when I change to the other tab and back everything seems to be OK. I have no idea what I could do to avoid that behaviour.
    many thanks

  18. partof

    Very great tutorial !

    But I have the same problem as Untouchab1e (Initially, both lists show up in the first tab). I use Android 2.1. I have searched but still not found why.
    If somebody knows, just in case… Thanks

  19. partof

    Actually I fixed it !
    You have to call “listView.setAdapter(…)” inside the createTabContent() method, instead of doing this before.
    I don’t really know why, but it does the job.

  20. Josh Post author

    @partof – Yes I had that problem as well. It has to do with the layout definition. I’ll try and update the layout to avoid this problem.

  21. Android Devices

    Nobody shares the coding in such detailed manner. When ever it comes to android devices when needs extra attention with coding to create something appealing.

  22. Nik

    Hi!

    I have some errors:
    -> listView1.setOnItemClickListener(new OnItemClickListener()…//Eclipse tells me the “setOnItemClickListener” arguments are wrong…(?)
    ->tabHost.addTab(tabHost.newTabSpec(LIST1_TAB_TAG).setIndicator(LIST1_TAB_TAG).setContent(new TabContentFactory() {…//Eclipse tells me the “setContent” arguments are wrong…(?)

  23. Pingback: Amazon Kindle Fire

  24. Dental Assistant

    What is interesting here is not just info, but style of presentation of information. Simply desire to say your article is as astounding. The clarity in your post is simply cool and I could assume you’re an expert on this subject. Waiting for more articles from you. Thank you so much!

  25. Larson Madren

    I was checking constantly this blog and I am impressed!
    I just wanted to give a quick shout out and tell you I really enjoyed reading this article. Thank you for the good information. I really enjoyed reading this article. Let me use it and hope it will work.

  26. André Heuner

    Regarding ….
    tabHost.setCurrentTab(1);
    tabHost.setCurrentTab(0);
    … hack: if you need it or not depends on the order of list views in the XML file;
    After rearranging two LinearLayouts I didn’t need the hack anymore.

  27. Josh Post author

    Yep you’re right – I fixed that as well – I should probably update the code to reflect this.

  28. Berlon

    Thanks for the tutorial.
    Could you give me some insight to populating the list from a database for the tab?

  29. julius

    I added tabs and other lists. The program is actually working just fine. But my Problem is that when I open the application, it seems like that the lists are on top of each other. But after you check all the tabs (selecting tab1 then tab2 then tab3..) the lists on the tabs would now be clear.

    What seems to be the problem?

  30. Samik R

    Great article. Were you able to update the code? I am getting the same problem of initially both lists showing up. I did not quite understand what Andre is saying above.
    Looking forward to updated code. Thanks.

  31. Samik R

    Actually, “Try adding android:visibility=”invisible” to the ListView tags in the layout.” – this suggestion works pretty well.

Leave a Reply

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


× 2 = twelve

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>