Search This Blog

Loading...

Wednesday, September 29, 2010

Experience - Multiple Android Activities in a TabActivity

The problem that I had was when I started a new activity it covered up the Tabs on my TabActivity. I could put a single Activity into a Tab, but adding a second Activity resulted in losing view of the Tabs. Then I learned about ActivityGroups which have a LocalActivityManager. I realized it was possible to have multiple Activities within an ActivityGroup after all this is what a TabHost does. I then realized if I set the content of each Tab to an ActivityGroup I could start multiple Activities in each Tab. I developed the below ActivityGroup.

import java.util.ArrayList;

import android.app.Activity;
import android.app.ActivityGroup;
import android.app.LocalActivityManager;

import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Window;

/**
* The purpose of this Activity is to manage the activities in a tab.
* Note: Child Activities can handle Key Presses before they are seen here.
* @author Eric Harlow
*/
public class TabGroupActivity extends ActivityGroup {

private ArrayList<String> mIdList;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mIdList == null) mIdList = new ArrayList<String>();
}

/**
* This is called when a child activity of this one calls its finish method.
* This implementation calls {@link LocalActivityManager#destroyActivity} on the child activity
* and starts the previous activity.
* If the last child activity just called finish(),this activity (the parent),
* calls finish to finish the entire group.
*/
@Override
public void finishFromChild(Activity child) {
LocalActivityManager manager = getLocalActivityManager();
int index = mIdList.size()-1;

if (index < 1) {
finish();
return;
}

manager.destroyActivity(mIdList.get(index), true);
mIdList.remove(index);
index--;
String lastId = mIdList.get(index);
Intent lastIntent = manager.getActivity(lastId).getIntent();
Window newWindow = manager.startActivity(lastId, lastIntent);
setContentView(newWindow.getDecorView());
}

/**
* Starts an Activity as a child Activity to this.
* @param Id Unique identifier of the activity to be started.
* @param intent The Intent describing the activity to be started.
* @throws android.content.ActivityNotFoundException.
*/
public void startChildActivity(String Id, Intent intent) {
Window window = getLocalActivityManager().startActivity(Id,intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
if (window != null) {
mIdList.add(Id);
setContentView(window.getDecorView());
}
}

/**
* The primary purpose is to prevent systems before android.os.Build.VERSION_CODES.ECLAIR
* from calling their default KeyEvent.KEYCODE_BACK during onKeyDown.
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//preventing default implementation previous to android.os.Build.VERSION_CODES.ECLAIR
return true;
}
return super.onKeyDown(keyCode, event);
}

/**
* Overrides the default implementation for KeyEvent.KEYCODE_BACK
* so that all systems call onBackPressed().
*/
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackPressed();
return true;
}
return super.onKeyUp(keyCode, event);
}

/**
* If a Child Activity handles KeyEvent.KEYCODE_BACK.
* Simply override and add this method.
*/
@Override
public void onBackPressed () {
int length = mIdList.size();
if ( length > 1) {
Activity current = getLocalActivityManager().getActivity(mIdList.get(length-1));
current.finish();
}
}
}


I got caught up trying to figure out if and how LocalActivityManager handled stepping back up the view hierarchy. After viewing the note on the LocalActivityManager.dispatchCreate(bundle state) which states "Note: This does not change the current running activity, or start whatever activity was previously running when the state was saved. That is up to the client to do, in whatever way it thinks is best."
I decided to add back tracking to the ActivityGroup. I attempted to make it behave the same as Activities outside an ActivityGroup by only needing to call finish() on an Activity and the previous Activity will be restarted or recreated.
I have also added the ability for the ActivityGroup to manage the back button being pressed. Android OS pre 2.0 handles things differently than the newer interface. A reference to this can be found here under Key Events Executed on Key-Up. I have tested the code on a device with OS 1.6 and the emulator with OS 2.1. Note: Child Activities like a ListActivity may handle the back button just override the appropriate methods for your OS version, and call onBackPressed() for the (parent) ActivityGroup. An example would look like this for OS 2.1.

@Override
public void onBackPressed() {
TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.onBackPressed();
}


The following section explains how I used this ActivityGroup. The first thing I did was subclass this ActivityGroup like this.

import android.content.Intent;
import android.os.Bundle;

public class TabGroup1Activity extends TabGroupActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startChildActivity("OptionsActivity", new Intent(this,OptionsActivity.class));
}
}


I added this TabGroup1Activity into my TabActivity like this.

TabHost tabHost = getTabHost();

tabHost.addTab(tabHost.newTabSpec("tab1")
.setIndicator("MESSAGES")
.setContent(new Intent(this, TabGroup1Activity.class)));


Then any Activity that you want to start in the ActivityGroup can be done in a way similar to this.

Intent frequentMessages = new Intent(getParent(), FrequentMessageActivity.class);
TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.startChildActivity("FrequentMessageActivity", frequentMessages);


And that is how I added multiple Activities with a back tracking ability to a Tab of a TabActivity. Remember to always add Activities to your AndroidManifest.xml. A sample project for this article can be found here.

161 comments:

  1. could you give your source code,i donot get the result
    wp19831014@gmail.com thank you

    ReplyDelete
  2. thank you .i have do it,but i have two question:
    1. how to end current activity in the ActivityGroup, if i use finish(),it end the app.
    2. how to deal with back key,if i press back, it back home
    i want to back activity

    ReplyDelete
    Replies
    1. // Back Button Pressed Event
      @Override
      public void onBackPressed() {
      YourGroupActivity.yourGroupActivityObjectActivity.back();
      }
      use this method if you have minimum sdk version 2.1

      Delete
    2. @Override
      public void onBackPressed() {

      YourGroup.group.back();
      };
      it works fine for me

      Delete
  3. Hi,
    I am facing problem in launching two activities in same tab.
    It will be helpful if you can pass me the source code. my email Id is dwarkesh10@gmailcom

    Thank you,

    ReplyDelete
  4. Thank a lot Eric.

    This would certainly help me a lot.

    -Dwarkesh

    ReplyDelete
  5. I updated the code to handle the back button. There still are several caveats including your OS version and if the child activity handles the back button. I also created a SampleTabs project that demonstrates everything in this article. Until I find a way to host it on my blogger account just leave a comment asking for it or my gmail is pretty easy to figure out eric.b.harlow. Also if this article or the sample project could help someone you know please spread the word.

    ReplyDelete
  6. Could you give source code, it's so difficult for me....
    mosaiclife@naver.com
    Thank you

    ReplyDelete
  7. Hello,I thank you for this tutorial. A download link for source code can help reader a lot or mail me at mangal.lal@rediffmail.com

    Thanks,
    Mangal

    ReplyDelete
  8. Hi..thanks for your great work. Could you please send the source code to my mail id gvenugopal141@gmail.com.

    Thanks,
    Venu

    ReplyDelete
  9. Now the sample code for this article can be downloaded. See the link at the bottom of the article. Comments are still welcome.

    ReplyDelete
  10. Thanks Eric..it helped me a lot.

    ReplyDelete
  11. Hi Eric..i need one more suggestion from you. Could you please tell me how to give animation effect to each activity that means when we call another activity it has to come from right to left.

    Thanks,
    venu

    ReplyDelete
  12. hi Eric,
    Could you please send an exam code of this.
    It will be very helpful for me
    "jony.cse@gmail.com"
    Your given source code not running in my pc, it shows error.
    Thanks
    Jony

    ReplyDelete
  13. @gvenu I don't have any experience with transition animations yet, so I may not be of much help. Look at this forum post. It may point you in the right direction.

    ReplyDelete
  14. Hi Eric..again i have one problem in my application with progress dialog. The same problem will also occur in your given sample application suppose if i add progress dialog in ArrowsActivity class as ProgressDialog pd = ProgressDialog.show(getBaseContext(), "","Loading...", true);
    Please give me your valuable suggestion to this problem.

    Thanks,
    venu

    ReplyDelete
  15. @gvenu I have not tested a dialog in the code yet, but I suspect it is the same issue as trying to have a spinner (drop down) in a child activity. They don't work yet. I do plan to look into this in the future, but I don't have time yet. I was going to start by looking into which activity child or parent is in focus and if they are both focusable. Maybe you could start there and if you discover anything I would be interested to know.

    ReplyDelete
  16. Eric, your code works great, got it up and running after I read the comment from Gvenu that Dialogs were causing a problem (still haven't looked into it.) I came across another issue and was wondering if you knew about it, seems OnCreateOptionsMenu no longer works within the child activity. I suppose it may as well be a focus issue, but wanted to check with you first.

    ReplyDelete
  17. One issue I found is a context error.

    Using getBaseContext() is an error and should be updated with getParent() in child activities and intents. All TabGroupActivity onCreate methods should update getBaseContext() to "this" -being a tabGroupActivity. Article and sample code should now reflect this change.

    I have included in the sample code how to call a spinner, and a dialog as well.

    ReplyDelete
  18. Your updated code helped solve my Dialog issues, but the options Menu problem still persist. I have tried grabbing the context of getParent() in MenuInflater inflater = new MenuInflater(getParent()); but that doesn't seem to solve the issue.

    ReplyDelete
  19. @Alejandro Huerta Try adding the following code to the TabGroupActivity.

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    return getCurrentActivity().onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    return getCurrentActivity().onOptionsItemSelected(item);
    }

    Also implement those methods (onCreateOptionsMenu,onOptionsItemSelected) in your activity to your liking. Do not return super methods as a result, instead simply handle with appropriate true or false logic.

    ReplyDelete
  20. Thank you, Eric. That did the trick and also very useful to know that some methods get caught in the TabGroupActivity and must then be handled from there.

    ReplyDelete
    Replies
    1. hai Alejandro ... would you pls help me......

      i am still stuck on the option menu...

      i am using the option menus for moving from one child activity to another..

      if you already fond a solution for this problem.. can you send me the source code??
      sankar.ranju@gmail.com

      Delete
  21. Hi Eric,
    unfortunately, search doesn't work with this solution. Pressing the search button on the second tab throws an exception... any solution to this?

    Thanks,

    Stefan

    ReplyDelete
  22. @haemi I don't have a complete solution or how to, but it simply hasn't been added to the TabSample project. Android documentation does a pretty good job of explaining search. Check it out here. Two general guidelines are use TabGroupActivity as the context, and remember some methods might need to be passed through TabGroupActivity to the ChildActivity.

    ReplyDelete
  23. @Eric Harlow
    You don't have to implement a search solution to reproduce the error. Even without your own search you can see that something's wrong, unfortunately. Clicking on the hardware-search-button on the first tab works, on the second the app crashes :(

    ReplyDelete
  24. I tried it out and I see what you mean. It is most unfortunate. The one interesting thing I found was it doesn't seem to be tab related. The only place it fails is in EditActivity which is a ListActivity. All of the other activities on either tab allow you to search. I have seen questions asking about ListActivity and this error. The only solution I have seen is here. I tried this with no success, so you may be out of luck.

    ReplyDelete
  25. @Eric Harlow

    it has to do with the listView.setAdapter()-method. If I remove that method, everything works fine. Adding just that single line => and the exception is back again. And I have NO idea why... :(

    ReplyDelete
  26. HI eric,
    Thanks a lot for your post.
    I have few doubts, is it necessary to call onkeyup and onkeydown methods in each and every child activity and intents.

    2) I have 5 tabs. from Tab 2 subactivity i have to go for tab1 subactivity, when it is tab2 subactivity i have to highlight my tab2 and when it is tab1 subactivity i have to highlight my tab1.
    3) BY your code we are maintaining only one tab activities.

    as android emulator your back is not functioning, any solutions to implement it.

    ReplyDelete
  27. @reddy In regards to your question about back. I am able to run the TabSample project as is without needing to have onKeyUp and onKeyDown in every child activity on a device that is OS 1.6 and emulator with OS 2.1. Are you getting an error message in TabSample when you press the back button on the emulator?

    ReplyDelete
  28. I come back here hoping you can help with this issue that I've been wrestling with. Everything in this code works fine, except that the options menu does not get recreated for each activity. If you open an options menu for a child activity, that menu will stay persistent even if you change to a different activity.

    I know that the issue is onCreateOptionsMenu(Menu) is called only once per activity and TabGroupAcitivy takes up that 1 time. The previous fix to solve menu's not being created was to Override and pass along the onCreateOptionsMenu(Menu) but it will only be passed along once, thus the options menu being the same for all child activities.

    I have tried using onPrepareOptionsMenu(Menu) but get a continuous loop ending in a StackOverFlow.

    I'm wondering if you can provide any insight or perhaps you've already solved this issue? Thanks in advance.

    ReplyDelete
  29. hi Eric,
    Could you please send an exam code of this.
    It will be very helpful for me
    "adahuang456@yahoo.com.tw"

    ReplyDelete
  30. @ada The link at the bottom of the article is the example code.

    ReplyDelete
  31. Hi Eric,

    Do you not find that your sample app leaks memory every time you attempt to destroy the activity within the activitygroup?

    Would appreciate your thoughts on this...

    ReplyDelete
  32. @Atric I was unaware. Never checked for a memory leak. Could you give me more details? Also I no longer use this code myself but I would like to improve it.

    ReplyDelete
  33. hi Eric,
    Could you please send an exam code of this.
    It will be very helpful for me
    thanks....please..
    "frdave@naver.com"

    ReplyDelete
  34. Hi Eric,
    Your post is very useful to android beginners like me.
    I have a doubt that can i use startActivityForResult() to start a child activity in our TabGroupActivity?

    Thanks in advance
    sathish.avunoori@gmail.com

    ReplyDelete
  35. Could you please email it to me at

    sheraz.jamshed@gmail.com

    ReplyDelete
  36. Hi Eric
    i try to use your code and it works
    A question: i have 3 tab button, each one with many activity
    When i start a new activity, it has the 3 tab button
    how i can start a new activity without the 3 tab button? can i hide them?

    Andrea
    tequila77xyz@libero.it
    Thanks in advance

    ReplyDelete
  37. @Andrea@Andrea

    i think this can just be done with startActivity() in your on click listener itself.
    make sure the destination activity is not in the tab widget. By doing this it will automatically hide the tab widget.

    ReplyDelete
  38. @Pradeep your solution work, i use this code:
    Intent intent = new Intent(context, TestActivity.class);
    startActivity(intent);

    instead of
    Intent ntent = new Intent(context, TestActivity.class);
    parentActivity.startChildActivity("TestActivity", intent);

    but now, when i click on the back button inside the TestActivity, to come back to the parent this code can't work:

    TabGroupActivity parentActivity = (TabGroupActivity) getParent();
    parentActivity.startChildActivity("TestParentActivity", new Intent(getApplicationContext(), TestParentActivity.class));

    how i can set the parent inside TestActivity ? i look for this method
    intent.putExtra
    but this method accept only String so i can't write this code
    intent.putExtra("TestParentActivity", TestParentActivity);

    ReplyDelete
  39. @Andrea I have not tested this to be sure but something that may help your back button issue would be to override onBackPressed() in your TestActivity if your are running OS 2.0 or greater. If you are running on an OS version before that (1.5,1.6) override onKeyDown and onKeyUp. The key thing to guarantee in either of these methods is to call finish() on TestActivity. If that doesn't work there is the method intent.putExtras(Intent) that may help the other thing you are trying.

    ReplyDelete
  40. hi,could you give your source code?
    My email is zhang096608@gmail.com

    ReplyDelete
  41. i created an activity group which activity 1 extend to it and set the onBackPress() in activity 2. but when i click on the back key while i am in activity 2, nothing happen. . .
    can someone tell me how to solve this?

    ReplyDelete
  42. Thanks.. It is very usefull..

    Keep doing good work. Best luck..

    Thanks,
    PiysuhNP

    ReplyDelete
  43. Hi, Eric Harlow. Thanks for this tutorial. But i have a problem, there is a EditText in one root tab activity, when the softkeyboard is open, then press back button, the acitivity will be exited instead of hiding the softkeyboard. Please giving me some clues, thanks again.

    ReplyDelete
  44. I'm curious if you handle orientation change any special way, or are you locked into either portrait/landscape. I'm trying to find a solution for transitioning the current state of the app across orientation changes.

    Thanks.

    ReplyDelete
  45. there are known issues while implementing startActivityForResult inside the tabs.Can anyone help override the setResult of startActivityForResult??

    ReplyDelete
  46. Even i am facing problems with startActivityForResult() and memory leaks while using this code. Please share if you find a solution.

    ReplyDelete
  47. hi friend.. can i get this source code
    jeeva_engg@rediffmail.com

    ReplyDelete
  48. Hi, I tried to use this example with an activity and a Listview populated by a simplecursoradapter. Then thing is that when It keeps crashing because ANR.Do you know how to implement this with a simplecursoradapter?

    ReplyDelete
  49. I´m also curious how to handle orientation changes.

    //Henrik

    ReplyDelete
  50. @Danny Palmer

    Did you manage to solve the orientation issue?

    ReplyDelete
  51. Hi thanks for this it help me lot.But me having some question in it like
    i am having three tabs tab1,tab2,tab3.View's to each tab is set.After click on tab1 it should go to the activity from where it is launch.
    e.g activity1 =>activity2(tab1 is set for this activity) .Now i want after click on tab it should go to activity1 from activity2

    ReplyDelete
  52. Hi

    I wounder if you could help me with some coding issue I have?

    Im trying to get a IMG button to open a new view from a tab. but when I implemet the onclick listener ( or any other way) the app crashes.

    Got any Idea?

    markman.electronics att gmail.com

    ReplyDelete
  53. @gvenu did you manage implementing the transition animation taking Eric multiple activities within tab approach? because I've been trying to implement this without any success

    ReplyDelete
  54. Thanks for the code. Works great for me.

    I was wondering, is it possible to open a tab from another tab?

    ReplyDelete
  55. thanks 4 the code.....hi..u put the progressbar here.............but i want a Alertdailog with listview inside the tab.....can u please suggest???????????????????

    ReplyDelete
  56. Hi,

    It gives above error because of the Context I was providing to alertdialog builder.

    Give:

    new AlertDialog.Builder(getParent()).setMessage(“Hello world”).show();

    We just need to call getParent() instead of AlertDialog.Builder(this)

    ReplyDelete
  57. Thank you very much for this. It worked like a charm.

    ReplyDelete
  58. @Blessan I am glad it is helpful. Hopefully I will be able to release a newer version this month with some updates and improvements.

    ReplyDelete
  59. Hi Eric....

    Awesome man.....its working great...
    Thanks for the code..

    ReplyDelete
  60. Hi, your tutorial is wonderful, and is there anyway I can have an animation for transition from one activity to another, both within the activity group?

    Thanks!

    ReplyDelete
  61. Hello Eric;

    I am working on same application. But i can't use back button. I have 3 tabs. Every tab has 4 activity(such as; A , B , C, D). i wanna go to A->B->C->D activity. And i wanna go back to D->C->B->A with back button. But back button can do this.
    I haven't solved this problem for 3 weeks.

    Please help me!

    I'm sorry my english is not good...

    ReplyDelete
  62. Hi Eric...thanks for this awesome tut..
    but I am facing "Force Close" error, when click on spinner which is in a child activity of parent activity in a tab. I am using this code ----

    COUNTRYLIST = getIntent().getStringArrayExtra("COUNTRYLIST");
    COUNTRYID = getIntent().getStringArrayExtra("COUNTRYID");

    countries = (Spinner) findViewById(R.id.leadCountry);

    ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, COUNTRYLIST);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    countries.setAdapter(adapter);
    countries.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView parent, View v, int position, long id){
    lcountry = parent.getItemAtPosition(position).toString();
    lcountryid = COUNTRYID[position];
    }
    public void onNothingSelected(AdapterView parent){
    }
    });

    ReplyDelete
  63. hi its great article. I am having a little confusion. If u send the source code then it will helpful for me. My email id :harish.grandhi@gmail.com

    ReplyDelete
  64. could you sedn me the source code please. jkerns119@gmail.com

    Thanks

    ReplyDelete
  65. PEFECT, i did add a finish() command from the overridden method onBackPressed since you don't let the user go back to the Android home screen, when they pressed the back key, anyway everything is working perfect...

    ReplyDelete
  66. Orientation resets everything though, thinking to do on OnResume...

    ReplyDelete
  67. @Michael Angelo

    Can you send the modified code?
    In my application, the back button leads to the android's home screen.

    ReplyDelete
  68. When pressing back from child activity the application closed and the home screen displayed.
    How it can be fixed?

    ReplyDelete
  69. A simple way to fix that is to override finishFromChild(Activity child) and call popTabContent() in it. Be careful with that as I ran into inconsistency issues and ended up overriding finishFromChild() and onBackPressed(). I didn't implement anything in either of this methods and instead call my popTabContent() in onKeyUp(int keyCode, KeyEvent event) like this

    /**
    * Overrides the default implementation for KeyEvent.KEYCODE_BACK
    * so that all systems provide a more consistent behavior.
    */
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
    popTabContent();
    return true;
    }
    return super.onKeyUp(keyCode, event);
    }

    ReplyDelete
  70. Can you send the popTabContent() code?

    ReplyDelete
  71. Hi,

    using this tutorial I got the following error:

    "Unable to start activity component info".

    Anyone know how to solve?

    ReplyDelete
  72. Thank you so much Eric your tutorial is very useful for my college work. God bless you man.

    ReplyDelete
  73. Excellent post dude, really helped us out!

    ReplyDelete
  74. Excellent tutorial but i have one problem:

    the TabActivity have a ActivityGroup that starts a new activity and this activity begins another activity.

    My problem is when the activity is paused automatically closes the application.


    ERROR/AndroidRuntime(7378): FATAL EXCEPTION: main
    ERROR/AndroidRuntime(7378): java.lang.NullPointerException
    ERROR/AndroidRuntime(7378): at android.widget.TabHost.dispatchWindowFocusChanged(TabHost.java:317)
    ERROR/AndroidRuntime(7378): at android.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:662)
    ERROR/AndroidRuntime(7378): at android.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:662)
    ERROR/AndroidRuntime(7378): at android.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:662)
    ERROR/AndroidRuntime(7378): at android.view.ViewRoot.handleMessage(ViewRoot.java:1923)
    ERROR/AndroidRuntime(7378): at android.os.Handler.dispatchMessage(Handler.java:99)
    ERROR/AndroidRuntime(7378): at android.os.Looper.loop(Looper.java:123)
    ERROR/AndroidRuntime(7378): at android.app.ActivityThread.main(ActivityThread.java:4633)
    ERROR/AndroidRuntime(7378): at java.lang.reflect.Method.invokeNative(Native Method)
    ERROR/AndroidRuntime(7378): at java.lang.reflect.Method.invoke(Method.java:521)
    ERROR/AndroidRuntime(7378): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
    ERROR/AndroidRuntime(7378): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    ERROR/AndroidRuntime(7378): at dalvik.system.NativeStart.main(Native Method)

    ReplyDelete
  75. Great tutorial! I have it working for basic functionality, but I'm having trouble with Animations. I have some animations that I want to run until the end, then once they're done, stay in their finished state. When another activity is started, I want them to remain in their finished state when the back button is hit, and returned to the Activity hosting the animations.

    The problem is that since the activities are started all over again, the animations run from the beginning each time the Activity is brought to the front again.

    Can you think of any way to mimic the normal behavior of activities, where the activities are "paused" and "resumed" when they lose and gain focus on the activity stack?

    ReplyDelete
  76. Update: Actually, all I had to do was configure the activity with the animations to use android:launchMode="singleTop", so when the LocalGroupManager fired off the intent, the same instance of the activity was used instead of creating a new one.

    ReplyDelete
  77. How do you assign a unique id to an activity?

    ReplyDelete
  78. Thanks for this solution, but I have one problem, same at mnemy in fact... but me, I can't set my activity to launchMode="singleTop" to resolve the problem, because I need multiple instance of the activity. Have you a solution for that ?

    ReplyDelete
  79. i am using ure source code for my application.
    I am not being able to create alert dialog.

    AlertDialog.Builder saveDialog = new AlertDialog.Builder(Setting.this);
    saveDialog.setTitle("Save Settings");
    saveDialog.setMessage("Are your sure?");
    saveDialog.setPositiveButton("Yes",
    new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    saveSettings();
    Toast.makeText(getApplicationContext(), "Your settings has been saved.", Toast.LENGTH_LONG).show();

    }
    });
    saveDialog.setNegativeButton("No",
    new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface arg0, int arg1) {
    clearFields();

    }
    });
    saveDialog.show();

    my error : badtokenexception

    ReplyDelete
  80. Thanks for the solution. Everything is working perfectly except the menu option. As mentioned by MetaStable, the option menu will be the same for all child activities once it enters the child's activities, it will not change back to the parent menu options even if the user change to other activities.

    Is anyone found any solution on this problem? Thanks.

    ReplyDelete
  81. @Robbins

    AlertDialog.Builder saveDialog = new AlertDialog.Builder(getParent());

    ReplyDelete
  82. Thx. that is very good example ^^

    ReplyDelete
  83. There is a pretty big bug - if you start from activity A an activity B and then finish() in activity A, the code above will actually finish activity B.

    ReplyDelete
  84. @Artem Russakovskii If you look closely at the method finishFromChild(Activity child) you can see that I designed it as a FILO stack. So when a finish() is called this method is current ending the activity on the top of the stack. If you want the behavior you mentioned I would suggest changing the implementation of finishFromChild.

    ReplyDelete
  85. Hi Eric,can you please tell me how can I use startActivityForResult() from my child activity?

    ReplyDelete
  86. Hi all, can someone please tell me how we can use startActivityForResult() from one of loaded activities? When I use that method, my onActivityResult() is not getting called.

    ReplyDelete
  87. Hi Eric, great job. I used ur code to start several activities in one tab. But i have a question. If the user press the backbutton u recreate the last Activity with:

    String lastId = mIdList.get(index);
    Intent lastIntent = manager.getActivity(lastId).getIntent();
    Window newWindow = manager.startActivity(lastId, lastIntent);
    setContentView(newWindow.getDecorView());


    Why do you so? In my case every time i press the back button my latest list will be recreated. So the activity call the server, get the response and show the list. Isn't this unnecessary?

    You could instead get the contentview from the last activity like this

    setContentView(manager.getActivity(lastId).getWindow().getDecorView());


    In one sentence: I does not understand why the activity has to be recreated instead of reused? It would be nice if u could explain that. ;)

    Greets from Germany

    ReplyDelete
  88. This comment has been removed by the author.

    ReplyDelete
  89. Ok, the problem above is because of the Flag "FLAG_ACTIVITY_CLEAR_TOP". If i remove this previous activities are resumed instead of created. I thinks this is more comfortable. Do u agree?

    ReplyDelete
    Replies
    1. Hey Benjamin,

      Am facing the same prob of the activity being recreated on pressing back....I want the activity to get resumed.
      Can u please point me in the right direction?

      Delete
    2. I have fixed some issues,you can refer to my code:
      https://github.com/pjq/ActivityGroupDemo

      Delete
    3. Hay Benjamin you got the point man..Thanks alot

      Delete
    4. let say if i remove FLAG_ACTIVITY_CLEAR_TOP then i can come back but if i again open the same/recent activity(activity from where i just came back) would not be open.
      any solution regarding this?

      Delete
  90. This worked perfectly! You're the man!

    ReplyDelete
  91. HellO! I am trying to use your code to call a camera intent but I am unsure how to use your code. Any ideas?

    ReplyDelete
  92. You Sir, are my hero. I've been looking for days for something that solves this particular problem. I've posed my questions multiple times on IRC without any reply.

    For the people above who can't get it to work: work this example out in a sample project and move on from there. This is as clear as water and as clear as he can make it.

    Thanks again for this life-saving post!

    ReplyDelete
  93. I'm having some trouble using the presented approach. I have an EditText on activity A, and when I start a child activity B (inside the same tab) and later return to activity A, the soft keyboard won't show up anymore.

    When switching to another tab and returning to the original one, the keyboard starts working again.

    Any ideas? Thank you!

    ReplyDelete
    Replies
    1. Hi Gustavo, did you find the answer for this problem?

      Delete
    2. Sadly no! I ended up modifying my app's screen flow and now I plan to never use a tab bar again. :)

      Delete
  94. Please, send me sources on slavadev@ukr.net
    Thanks in advance)

    ReplyDelete
  95. Could you send me the sources, please? This is my email address, thank you for your contribution:

    luk2.86tk@gmail.com

    regards.

    ReplyDelete
  96. I have a question, I have two Tabs A y B, inside Tab A i have activity 1, activity 1 launches activity 2, then i select Tab B with activity 3 then return to Tab A, but Tab A display activity 1 when the last activity was activity 2, why is this happenning?, how can i mantain the activity tab state ?.

    Best Regtards.

    ReplyDelete
  97. Regarding the issue with onActivityResult

    The solution is override onActivityResult at TabGroupActivity and then route the received values to the current activity

    Activity current = getLocalActivityManager().getCurrentActivity();

    ReplyDelete
    Replies
    1. Hi, thanks for confirming where to capture the intent result. However: exactly how are you supposed to trigger the onActivityResult on the current (real, not TabGroup) activity?

      If you in the @Override TabGroupActivity.onActivityResult try the following
      Activity current = getLocalActivityManager().getCurrentActivity();
      current.onActivityResult(reqCode, resultCode, data);

      you notice that onActivytResult is NOT visible. It's protected and thus the TabActivity does not have access to it. I do not want to write another metamethod and ugly casting (to your specific Activity) which would add additional overhead to the scenario.

      This whole TabGroup & Activity intercommunicatin issue is starting to cost alot more than it tastes. Has any1 tried simply having one Activity per tab and handling all subviews as simple views which you switch out? After all the issues I'm most def. leaning towards such a solution.

      Delete
  98. Hi i use your class TabGroupActivity class your but when i click the back button of the child activity it reload the activity i don not want to reload that i only want to display its previous state.same as normal android application can do.
    please help me as early as possible.

    ReplyDelete
  99. @Hiram Fernandez

    hi Hiram.

    Can you explain abit about onActivityResult problem. Like how to call startActivityForResult, how to make onActivityResult fire =.=

    Thanks you.

    ReplyDelete
  100. Thank You .... :)
    No words I searched Everywhere.
    Mahe

    ReplyDelete
  101. Hi Eric,

    I am using the Activity group for designing Tab bar.I am facing one small issue that is "I have list view in my first tab.when I click on the list item I am going to another activity(act2). when I press back button from 'act2' act2 is closing and at a time First Tab activity also closing.

    Note:It is happening 2 times out of 12 times.

    Could you please give solution for my problem?

    ReplyDelete
  102. Hi I have a question. If i want the user touch the tab every time start first activity not the child what leave before then i where recreate the mIdList?

    My idea if leave the tab to other tab then i clear the mIdList and if the user back the tab then show the first activity :) Just where clear?

    thx

    ReplyDelete
  103. Thank you very much for this article...... from 3 days i tried and searched for concept..... here i got..... Thanks again

    ReplyDelete
  104. Hello!

    I have small problem with sample! If i click to "Next" button on option page and rotate the screen to "Landcape mode", app go automatically back to first activity in group. Whay this?

    ReplyDelete
  105. Hi,

    The tutorial is of great help.

    But I am facing an issue with saving the state of an activity. Say I am in Activity A with some content in it which is fetched from web service. Now, on a button press from Activity A the app goes to Activity B. Coming back to Activity A should have the same content that was there but it do not happens so. Can you please suggest a way of saving the state in activity group.


    Thanks
    Sunil

    ReplyDelete
  106. Hi sunnil.softweb! I think we got the same problem... if you find the solution, please leave comment here!!! Thanx!!!

    ReplyDelete
  107. Hi Nevro,

    I am looking into it and it seems the startChildActivity method in TabGroupActivity sets the clear top flag and may be that's the reason it behaves in such a manner. I tried by removing that flag but then the list item onItemClick is called only once which is really strange.

    I will surely post here if I find anything.


    Thanks
    Sunil

    ReplyDelete
  108. Hi i have been using your code as the base of my application
    and I have structure like this
    MainActivity -> TabGroupActivity1 -> Activity1 -> Activity2.

    now I want to redirect on activity2 only if the flag is true
    i am using something like this

    if(flag){
    Intent previewMessage = new Intent(getParent(), ArrowsActivity.class);
    TabGroupActivity parentActivity = (TabGroupActivity)getParent();
    parentActivity.startChildActivity("ArrowsActivity", previewMessage);
    }else{
    setContentView(R.layout.row);
    next = (Button)findViewById(R.id.button1);
    Button back = (Button)findViewById(R.id.button1);
    }


    but it is not working If i redirect on some click events it work but if i do somthing like this it is not working

    Please help me with this

    Thank you

    ReplyDelete
  109. Hey,
    Thanx for the great tutorial.

    Although everythings working jus fine but in one of the child activities i am using spinner(for drop down) and a timePickerDialog.

    On clicking the spinner and the timepickerdialog i am getting this error
    ----------------------------------------------------------
    02-04 17:40:01.993: ERROR/AndroidRuntime(354): android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord@44f03200 is not valid; is your activity running?
    ----------------------------------------------------------
    Could anyone please help me out.

    Thanks & Regards.

    ReplyDelete
    Replies
    1. Hi Mohamad,

      I'm also facing the same problem.

      Can you update me, if you find any solution for this?

      Regards,
      Gopalan

      Delete
    2. If you are creating your spinner/timePickerDialog using "this", change "this" to "getParent()"
      Worked for me...

      Delete
  110. Hey there,
    This is really a great tutorial. I just wanted to say thanks.
    Keep up the good job.

    ReplyDelete
  111. Found solution for doing animations when switching Activity in ActivityGroup. Just add below methods in your custom ActivityGroup class

    public Animation inFromRightAnimation() {
    Animation inFromRight = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, +1.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
    inFromRight.setDuration(500);
    inFromRight.setInterpolator(new DecelerateInterpolator());
    return inFromRight;
    }


    public Animation outFromLeftAnimation() {
    Animation outFromleft = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -1.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
    outFromleft.setDuration(500);
    outFromleft.setInterpolator(new AccelerateInterpolator());
    return outFromleft;
    }

    and put
    window.getDecorView().setAnimation(inFromRightAnimation());
    before setContentView(window.getDecorView());

    in both startChildActivity and finishfromChild methods

    ReplyDelete
  112. Here is a ActivityGroup Bug
    See the details:http://code.google.com/p/android/issues/detail?id=10083

    The following methord is wrong in LocationActivityManager:
    public Window destroyActivity(String id, boolean finish) {
    LocalActivityRecord r = mActivities.get(id);
    Window win = null;
    if (r != null) {
    win = performDestroy(r, finish);
    if (finish) {
    mActivities.remove(r);
    }
    }
    return win;
    }

    ReplyDelete
  113. https://github.com/pjq/ActivityGroupDemo

    ReplyDelete
  114. Has anyone fixed the issue with the search dialog not displaying when you click on the search hardware button?

    ReplyDelete
  115. hi is this method deprecated? , is it better to go with fragments for this kind of task? thanks ;)

    ReplyDelete
  116. Thank you very much, very helpful..

    ReplyDelete
  117. Hi...
    I hav a pblm on my code,pls give me solution...
    I created two tabs on main activity, on clicking the first tab it shows the listview1 and cliking the second tab it shows the other listview2... i dnt knw how to do... pls give me the code for it..

    ReplyDelete
  118. ActivityGroup is depricated do you have the same example using Fragment and FragmentManager

    ReplyDelete
  119. Soooooooooooooo nice and good. it helps me a lot.

    and better to go the following links there you can some code

    https://github.com/pjq/ActivityGroupDemo

    http://stackoverflow.com/questions/1306689/launching-activities-within-a-tab-in-android

    ReplyDelete
  120. i'm very thankful to you as i was stuck with the same problem.good work.

    ReplyDelete
  121. Hello Eric,
    I am facing problem in launching two activities in same tab.
    It will be helpful if you can send me the source code. my email Id is satishkolawale2@gmail.com

    Thanks

    ReplyDelete
  122. On pressing Back key no events occurs.I want to get back to menu page.

    ReplyDelete
  123. thanx a useful tutorial...

    but i have a doubt . iam implementing a option menu.. on one of the child activity...
    on the item click i start another child activity... but its not woking...
    how the option menu is implemented on the activity group.

    ReplyDelete
  124. can u mail me source code of this program..
    m not able to run it..
    my mail id is nik.shah41@gmail.com

    ReplyDelete
  125. Thank you so much for your tutorial,
    I have bugs with this code. Whenever I click back button my app goes to force close state. I'm tried 3 days to clear this bug but not able clear it. Please help me and I was test this with Android OS 4.0.4. Thanks in advance.

    ReplyDelete
  126. Intent lastIntent = manager.getActivity(lastId).getIntent();
    This line gives NullPointerException while I'm tried to go back by pressing back button.

    ReplyDelete
  127. Since you are using Android 4.x ActivityGroup is deprecated. I would suggest you use the ActionBar, FragmentManager, and Fragments instead.

    ReplyDelete
  128. Hi i am tab activity and i am facing some prob.. please help me.
    I have two tabs Tab1,Tab2.
    Tab1 contains Activity1 which has a listview ,so when i click on the listview items, it should open another activity which contains some data .i want that data to send back to Activity1 .

    Now i am able to send the data back to Activity1 but both tabs are missing. I want both tabs Tab1,Tab2 should be there. I have already used ActivityGroup class along with replacecontentview(),but that did not helped.

    ReplyDelete
  129. Thank u some much for this awesome tutorial..It helped me a lot...

    ReplyDelete
  130. Hi Eric,
    It's really a great tutorial to enjoy. I used your tutorial to launch my activities in TabGroupActivity.
    Please help me for the below situation. I am stuck here :(
    I launched my child activity as given below from the first activity:
    try {
    TabGroupActivity parentActivity = (TabGroupActivity)this.getParent();
    Intent intent = new Intent(InstagramMainActivity.this,InstagramPhotoDetailActivity.class);
    intent.putExtra("Index", (int)adapter.getItemId(position));
    parentActivity.startChildActivity("InstagramPhotoDetailActivity",intent);
    }
    catch (Exception e) {
    Intent intent = new Intent(_myActivity, InstagramPhotoDetailActivity.class);
    intent.putExtra("Index", (int)adapter.getItemId(position));
    startActivityForResult(intent, 1);
    }
    And then in second activity again I used the same above code, but with different activity name, and for the third one. So now my mIdList contains 3 activities. But as soon as I launched third activity from the previous one, its not getting started. I tried to debug and come to know that my third activity's onCreate method is being called three times, i.e. number of elements in the mIdList and my app crashes.
    Plese suggest me the ideal way of keep launching the child activities from the parent and so on.
    Also if I back pressed the button, instead of going back to previous parent activity, my activity comes back to home screen, i.e. first activity of the TabGroupActivity
    Waiting for your kind reply..
    Thanks

    ReplyDelete
  131. Hi Eric,
    I have a case where i need to open a mapv2 fragement activity from a listview in a tab,wen i cick the tab,listview comes first and after clicking the listview,the map shows all wraps inside one tab is that possible to do that in tabgroup activity,cause my map shows a white screen,but it opens wen called without using tabgroup,please help me i am stuck here

    ReplyDelete
  132. could you please send me your source code, i cant get hold of it.

    sfaisalawan84@gmail.com

    ReplyDelete
  133. Hi Eric, I followed your blog here and tab contents are working fine. But issue with Async task not populating a ListView as it cannot find token window or related to Context not right? What do you think?

    http://stackoverflow.com/questions/16758401/android-how-to-add-sherlock-actionbar-to-slidingactivity-and-progressdialog-sh

    ReplyDelete
    Replies
    1. I am at sebastian_cheung@yahoo.com if you could reply directly it would be highly appreciated.

      Delete
  134. Hello,

    I am using TabGroup in my application. There are four tabs, Tab1, Tab2, Tab3, Tab4. Default tab is Tab1.The normal flow in Tab3 is Page1 -> Page2 -> Page3 -> Page4 where Page1 extends TabGroupActivity. My application can also receive push notifications. So when a notification is received I want to open page4 in Tab3. And on the back button of page4 the flow should be Page4 -> Page3 -> Page2 -> Page1. Any idea, how to implement this?

    ReplyDelete
  135. This comment has been removed by the author.

    ReplyDelete
  136. Thanks eric harlow..you made my day man..Thanks alot

    ReplyDelete
  137. I got total 4 tabs. My 2nd and 3rd tab cannot finish(). Reason?

    ReplyDelete
  138. Hi..thanks for your great work. Could you please send the source code to my mail :nonelela.baneti@gmail.com.

    ReplyDelete
  139. Hi can you mail me the source code .... please

    smriti005005@gmail.com

    Regards::
    smriti

    ReplyDelete
  140. Thanks a for sharing knowledge really appreciating !!!

    ReplyDelete
  141. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hi..

      when onBackPressed() call at that time previous activity is destroy and call it's all life cycle..

      onCreate()
      onStart()
      onResume()
      onStope()
      onDestroy()

      but i want, When user onBackPressed()

      at that time user not destroy previous activity but Resume previous acivity..

      please help me.

      Thank You,
      Bhavesh Vadalia

      Delete
  142. Hi..thanks for your great work. Could you please send the source code to my mail id ahirvishnu@gmail.com

    ReplyDelete
  143. Hi all
    If I want intent from Activity to ActivityGrop how i do ?

    ReplyDelete
  144. Very well buddy. Very Usefull & truthfull demo till this date.
    Keep it up.

    ReplyDelete