Use Android ActivityGroup within TabHost to show different Activity

Nico Heid's picture

android

there is an updated version to this article with some improvements. please also read: Android ViewFlipper within TabHost for Tabs with different Views ... and better memory footprint.

When you're using a TabHost each tab has it's own Activity. Now image you want to change the Activity for a certain tab. If you just go on and create a new Activity and display it, your Tab Layout is no longer visible.

For that reason you need a ActivityGroup within the Tab where you want to change the Activity.
An ActivityGroup is: A screen that contains and runs multiple embedded activities.

Let's look at this at a real life example. An Android app that shows your podcasts. In the first Activity you get to see all podcasts by subscription. If you touch the subscription, you see the single podcasts you've downloaded for that subscription.

The Tabhost contains three tabs, one for the MediaPlayer, one for the archive and one for available downloads.

  1.         TabHost tabHost = getTabHost();
  2.  
  3.         tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("Player").setContent(
  4.                 new Intent(this, PlayerActivity.class)));
  5.         tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("Archive").setContent(
  6.                 new Intent(this, ArchiveGroup.class)));
  7.         tabHost.addTab(tabHost.newTabSpec("tab3").setIndicator("Updates").setContent(
  8.                 new Intent(this, DownloadList.class)));

The ArchiveGroup takes care which Activity is shown in the second tab. With setContentView you can bring the View to the front.

  1.         View view = getLocalActivityManager().startActivity("ArchiveActivity",
  2.                 new Intent(this, ArchiveActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
  3.        
  4.         setContentView(view);

Now all you need to do is to bring another View to the front after an action is triggered. In this case, after a ListItem is clicked.

  1.         String album = (String) getListView().getItemAtPosition(position);
  2.         Intent intent = new Intent(getApplicationContext(), ArchiveAlbums.class);
  3.         intent.putExtra("album", album);
  4.         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  5.        
  6.         View view = ArchiveGroup.group.getLocalActivityManager().startActivity("ShowPodcasts", intent).getDecorView();
  7.        
  8.         ArchiveGroup.group.setContentView(view);

You need to tell the ActivityGroup which view is to be on top and set the appropriate Flag, so that the View will be on top.

Of course now you have to keep track which activity is in front, how they behave and what happens if the back button is pressed. But that gives you room for customizing the behavior.

The full code can be found on github in the GpodRoid project.

Another good tutorials are by H. Larsen and Eric Harlow.

Comments

 Twitter Trackbacks for Use Android ActivityGroup within Tab's picture

[...] Use Android ActivityGroup within TabHost to show different Activity | united-coders.com united-coders.com/nico-heid/use-android-activitygroup-within-tabhost-to-show-different-activity – view page – cached When you're using a TabHost each tab has it's own Activity. Now image you want to change the Activity for a certain tab. If you just go on and create a new Activity and display it, your Tab Layout is no longer visible. Tweets about this link [...]

Mark Murphy's picture

Pop open hierarchyviewer on your app sometime. Having activities-in-tabs, let alone activity-groups-in-tabs, chews up a lot of stack space, represented in hierarchyviewer as additional depth in your view hierarchy. Using your technique, developers are increased risk of OutOfStackExceptions. It also requires more code than simply having views-in-tabs, uses more heap space than simply having views-in-tabs, etc. Any UI that can be represented by activities-in-tabs can be implemented as views-in-tabs.

Even navigation within a tab can be done simply via a ViewFlipper as the container. And, since ViewFlipper lets you remove things (unlike ActivityGroup, AFAICT), you have better memory management control this way.

Nico Heid's picture

i will look into it.

Anonymous's picture

Hi,

I have tabhost with multiple activities, in first activity i have button when i click this button, i need to display second activity without loosing my tabhost and header, once i get my second activity in this also i have 2 button when i click first button, it should go back to my first activity and when i click second button it should go back to third activity. i did coding using the following

  1. Intent activityCurrentSummaryIntent = new Intent(v.getContext(),
  2.                                                  currentsummary.class);
  3. activityCurrentSummaryIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  4.                                
  5. View view = ArchiveGroup.group.getLocalActivityManager().startActivity(
  6.                 "ShowPodcasts",  
  7.                 activityCurrentSummaryIntent).getDecorView();
  8. ArchiveGroup.group.setContentView(view);
  9.  
  10. // or
  11.  
  12. replaceContentView("currentsummary", activityCurrentSummaryIntent);
  13.  
  14. public void replaceContentView(String id, Intent newIntent) {
  15.   LocalActivityManager mLocalActivityManager = getLocalActivityManager();
  16.   View view = mLocalActivityManager.startActivity(id,newIntent.addFlags(
  17.                           Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
  18.   this.setContentView(view);
  19. }    

when i click button i am getting stopped unexpectedly error. Could you please suggest solution for this as early as possible,

Thanking you in advance

WIth Regards,
Roy

Nico Heid's picture

you have a working example for that?

Sundar's picture

In this iam getting TabHost error.could me send me a program to my mail-id for tab layout without any errors??

Anonymous's picture

In the above code ArchiveGroup.group is not working error appeared at that place in the below replaceContentview is working but am require the ArchveGroup.group is required.please give the suggestion.

Sayan's picture

Even I'm facing the same problem. If you have a working example can you please forward it my mail address.

Android ViewFlipper within TabHost for Tabs with different V's picture

[...] article is a follow up of Use Android ActivityGroup within TabHost to show different Activity. As you probably noticed or read in the comments, the provided solution in the last article was [...]

JBM's picture

Hi Nico,
The ArchiveGrop tab with different activities is real nice. How can we go back to the first view in the tab, after launching the second activity from the List View? -- Basically, if I clck on the back button, the whole application closes..... Any idea. Thanks

Nico Heid's picture

if you see the back button, do your own magic. e.g. going to the specific tab and don't send it to the superclass via super.onKeyDown.
Like this:

  1.  public boolean onKeyDown(int keyCode, KeyEvent event) {
  2.         if ((keyCode == KeyEvent.KEYCODE_BACK)) {
  3.               // do your magic
  4.            }

Just make sure you apply it the way, a user would expect the behavior to be. Go back to the previous screen or leave the application when appropriate.

Matt Ingram's picture

how would you go about starting an activity, for instance i wanna take photos from an action off an activity in the group, but i want the camera to have full screen, not be constricted to inside the tabs? any ideas?

thanks,
matt

Nico Heid's picture

just start the cam as new activity. it will be full screen then.
i added an example in the demo, you can find it here: https://github.com/nheid/unitedcoders-android

Stephane's picture

Hi,

I use the same code as you, but i have an exception. I don't know why!
EXCEPTION : Unable to start activity ComponentInfo {intent to start name} android.view.WindowManager$BadTokerException: Unable to add window -- token android.app.local

Does anyone have any idea please?

Thanks

Nico Heid's picture

there's a discussion about it here:
http://stackoverflow.com/questions/1561803/android-progressdialog-show-c...

seems specific to api version or how your current context is.

zekt0r's picture

I have the same problem. How can you solve?

Anonymous's picture

tabhost problem

Tarun Aggarwal's picture

Hello all,

I have divided my android screen in two parts in one part i put my own app and in second part i want to insert a tab host, widget and it needs to extend my main class but the main class is already extended to some activity used by my first app. Is there any way to extend my main class by any other method ? Can anyone please help me in this ??

any kinda help would be appreciated !!

Nico Heid's picture

i can't follow you.
maybe draw a sketch or refer to some code, please?

Sumant's picture

Thnx for this great post.
But mw having few q's

1)TabBar is present in my activity.The first tab is having an Button "submit". After click on submit is should go to second tab i.e. that ta should get opened.
Now in this what is mentioned is that after click on button the content of the next activity is displayed on the current activity but i want that after click on button it should move to the next tab.

i want to move the tab and not it's content also i want tab bar should present there.
Thanx for any help...................

Nico Heid's picture

if i understand your button does some magic. is it starting an activity?

if the button should switch the tab, you have to switch tabs in the eventhandler
see: http://developer.android.com/reference/android/widget/TabHost.html#setCurrentTab(int)

Sumant's picture

Hi, thnx for reply.

I have tried this before but it is not working it is giving null pointer exception.

Also regarding button magic onclick of button i have started another activity.

My first tab is set by using tabHost.setCurrentTab(0) i.e. tab 0 is selected.

Now Tab 0 is having button after click on button tab1 should got selected.

tabs.java is my activity which extends Tab Activity. tab 0 is having activity1 ,tab1 is having activity2 & so on.....
after click on button it is showing the next activity on current activity with same tab is selected not the one which is holding that activity

Sumant's picture

Hi,
Now i am able to get the next activity call on current activity in tabbar and it work fine.As mention in above tutorial.
But after click on tab i want to replace the next view which i am displaying on current view should replace with older view.
E.g.tab1 ,tab2,tab3.After click on tab1 it should open the activity which is specified in tabactivity.

Thanks in advance for any help suggestion...

sambit's picture

This tutorial is real very help full.
I have tired is implement the same in my project but I m facing problem.
Onclicking on the CityActivity I am starting the ShowCity Activity,in which i am givivng some user input but after setResult() my parent onActivityresult is not getting called.
Any solution of how to get the result back from a activity.

Mike's picture

i was trying to do your implementation somehow i can;t execute it? do you have the code for this example?

Nico Heid's picture

the project moved, so the link was dead.
I corrected it.

you can jump directly to a activity with a tabhost here:
https://github.com/gpodder/GpodRoid/blob/master/src/com/unitedcoders/and...

nico

Nikhil's picture

Hi,
I tut is good to know... but now I want to refresh the view in activitygroup everytime it is loaded or comes on front.
How can I do that
Please reply.
Its urgent
Nikhil

Sayan's picture

If you have a working example for switch between activities on button click within the tab-host without loosing tab & Header, can you please forward it my mail address??

Joe's picture

Thanks very much~~~~~

Finally solve my problem!

Himanshu's picture

Hey I have 2 tabs. So i have the main activity and two more activities for the 2 tabs. The first tab(activity) has a listview. What i want is when i click on a item in the list a new activity starts in the same tab. The java file containing the listview extends ListActivity. Now if i follow ur tutorial to start a new activity the class should extend ActivityGroup. If i make the java file containing the listview extend to ActivityGroup instead of ListActivity then it gives error in the setListAdapter() and getListView() functions. Can u please help me with this?

venkatakumar's picture

The tutorials looking good i want to display a map in on of the tab. can u tell me the code.

Manish's picture

Hi,
I have use the same approach to develop an app where I have 3 tabs and each tab has its own ActivityGroup. I have menus for each activity. But when I press menu button, the menu does not appear. After doing some random trails I found that If I implement onCreateOptionsMenu in ActivityGroup then only menu appears. I am not able to execute onCreateOptionsMenu of Activity.
Please suggest how to use menu of Activity as I have many activities in single ActivityGroup and by implementing onCreateOptionsMenu in ActivityGroup is not the right way to handle this problem.

Thanks.

Kenny's picture

This was a tremendous help! I do have one issue tough. Tab1 onCreate launches Activity1. Clicking on a list item in Activity1 will launch Activity2. Clicking on a list item in Activity 2 launches Activity3. If I hit the back button on Activity3, it goes back to Activity1 closing Activity3 and Activity2. I want it to show Activity2, rather than closing 2 activities at once. Does anybody else have this problem?

Thanks in advance.

- Kenny

Amit Saha's picture

I have tabhost with five activities. Each activity has four child activity. when I enter in the child activity I did not go back to the main activity in the tabHost.

Please help to resolv this problem.

Nikhil's picture

Hi,
I tut is good to know... but now I want to refresh the view in activitygroup everytime it is loaded or comes on front.
How can I do that
Please reply.
Its urgent
Nikhil

Yatibawri's picture

Hi,
I have four tabs under TabActivity.Say 1, 2, 3, 4
I go on 1st tab then 2nd then 3rd and now if i want to go back to the
last pressed tab then wat shud i do for that.
I tried many other options using Activity group but all finishes the application .

Please if you can help me out..
Thanks

Anonymous's picture

I have a page showing some data with Spinner activity and a listview activity. On selection of Spinner item I populate listview item, onclick of the listview item I show some description in a separate Activity. I have tabs in my page. To get tabs on the listview selection activity I created a ListviewGroup acvity and followed the code specified here.

Now when I select an item in the spinner I am getting an error and the log cat error is this:
02-21 16:27:41.149: ERROR/AndroidRuntime(858): android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord@40520218 is not valid; is your activity running?

02-21 16:27:41.149: ERROR/AndroidRuntime(858): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)

Can someone help me here.. Thanks

lijun's picture

thanks very much !

View view = ArchiveGroup.group.getLocalActivityManager().startActivity("ShowPodcasts", intent).getDecorView();

ArchiveGroup.group.setContentView(view);

but what is "group"? why the "group" is not defined in my code and need to creat ??