Search code examples
androidandroid-fragmentsandroid-activity

Switching between Fragments in a single Activity


I want to create an Activity which shows a sort of menu a user can go through. By clicking an item, a new screen is shown, allowing the user more options (wizard-like).

I wanted to implement this using Fragments, but it's not working for me.
Right now I have:

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:id="@+id/main_fragmentcontainer" >

    <fragment
        android:id="@+id/mainmenufragment"
        android:name="com.myapp.MainMenuFragment"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

    <fragment
        android:id="@+id/secondmenufragment"
        android:name="com.myapp.SecondMenuFragment"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

MainMenuFragment with an OnClickListener:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.mainmenu, container, false);

    setupButton(view);
    return view;
}

/* Button setup code omitted */

@Override
public void onClick(View v) {
    SherlockFragment secondRunMenuFragment = (SherlockFragment) getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.secondmenufragment);
    FragmentTransaction transaction = getSherlockActivity().getSupportFragmentManager().beginTransaction();

    transaction.replace(android.R.id.content, secondMenuFragment); //also crashes with R.id.main_fragmentcontainer
    transaction.addToBackStack(null);
    transaction.commit();
}

Now when I press the button, the application crashes with this logcat:

06-27 01:45:26.309: E/AndroidRuntime(8747): java.lang.IllegalStateException: Can't change container ID of fragment SecondMenuFragment{405e2a70 #1 id=0x7f060029}: was 2131099689 now 2131099687
06-27 01:45:26.309: E/AndroidRuntime(8747): at android.support.v4.app.BackStackRecord.doAddOp(Unknown Source)
06-27 01:45:26.309: E/AndroidRuntime(8747): at android.support.v4.app.BackStackRecord.replace(Unknown Source)
06-27 01:45:26.309: E/AndroidRuntime(8747): at android.support.v4.app.BackStackRecord.replace(Unknown Source)
06-27 01:45:26.309: E/AndroidRuntime(8747): at com.myapp.MainMenuFragment$MyButtonOnClickListener.onClick(MainMenuFragment.java:52)

What am I doing wrong?


Solution

  • Personally, I would not have any <fragment> elements.

    Step #1: Populate your activity layout with a <FrameLayout> for the variable piece of the wizard, plus your various buttons.

    Step #2: In onCreate() of the activity, run a FragmentTransaction to load the first wizard page into the FrameLayout.

    Step #3: On the "next" click, run a FragmentTransaction to replace the contents of the FrameLayout with the next page of the wizard.

    Step #4: Add in the appropriate smarts for disabling the buttons when they are unusable (e.g., back on the first wizard page).

    Also, you will want to think about how the BACK button should work in conjunction with any on-screen "back" button in the wizard. If you want them to both behave identically, you will need to add each transaction to the back stack and pop stuff off the back stack when you handle the "back" button.

    Someday, if nobody beats me to it, I'll try to create a wizard-by-way-of-fragments example, or perhaps a reusable component.