Tumetsu
Tumetsu

Reputation: 1721

Fragments inside tabs

I'm creating menu which has two tabs. Each tab has three fragments which show the content. I though this would be straightforward but after experimenting and Googling it looks like I were wrong.

I managed to create fragments to the first tab. However, when I change to other tab and back, I get the following error message and app crashes:

07-11 16:49:57.829: E/AndroidRuntime(20009): FATAL EXCEPTION: main
07-11 16:49:57.829: E/AndroidRuntime(20009): android.view.InflateException: Binary XML file line #8: Error inflating class fragment
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:697)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:739)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at com.machinedata.ui.feedback.UsersFragment.onCreateView(UsersFragment.java:16)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:828)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1032)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.app.BackStackRecord.run(BackStackRecord.java:622)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1382)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.app.FragmentManagerImpl$1.run(FragmentManager.java:426)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.os.Handler.handleCallback(Handler.java:605)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.os.Handler.dispatchMessage(Handler.java:92)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.os.Looper.loop(Looper.java:137)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.app.ActivityThread.main(ActivityThread.java:4507)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at java.lang.reflect.Method.invokeNative(Native Method)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at java.lang.reflect.Method.invoke(Method.java:511)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:978)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:745)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at dalvik.system.NativeStart.main(Native Method)
07-11 16:49:57.829: E/AndroidRuntime(20009): Caused by: java.lang.IllegalArgumentException: Binary XML file line #8: Duplicate id 0x7f0b0013, tag null, or parent id 0xffffffff with another fragment for com.machinedata.ui.UserListFragment
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.app.Activity.onCreateView(Activity.java:4252)
07-11 16:49:57.829: E/AndroidRuntime(20009):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:673)

Now my tabs are fragments themselves, which are placed dynamically to the screen. These fragments then inflate xml-files which have fragments placed in them statically. After some googling I found out that placing fragments inside fragments is a bit tricky.

getChildFragmentManager works in API level 17, but I'd like to keep API level in 14. Is there anyway to create this kind of menu structure? Do I need to create separate Activities for tabs?

Here is my activity which displays the tabs:

    public class FeedbackActivity extends Activity implements UserListFragment.OnItemClickedListener
{

    private ToplistsFragment toplist;
    private UsersFragment users;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        setContentView(R.layout.feedback_screen);

        //create tabs for dashboard and graphs
        ActionBar.Tab tab1 = actionBar.newTab().setText(R.string.feedbackUsers);
        ActionBar.Tab tab2 = actionBar.newTab().setText(R.string.feedbackToplist);
        toplist = new ToplistsFragment();
        users = new UsersFragment();
        tab2.setTabListener(new MyTabsListener(toplist));
        tab1.setTabListener(new MyTabsListener(users));
        actionBar.addTab(tab1);
        actionBar.addTab(tab2);


    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
            ContextMenuInfo menuInfo) {
        // TODO Auto-generated method stub
        super.onCreateContextMenu(menu, v, menuInfo);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // TODO Auto-generated method stub
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
    {
        // TODO Auto-generated method stub
        Log.v("log","ID: " + item.getItemId() + " " + item.getTitle());
        switch (item.getItemId()) 
           {        
              case android.R.id.home: 
                  Intent intent = new Intent(this, ModeSelectActivity.class);
                  startActivity(intent);        
                 return true;    


              default:            
                 return super.onOptionsItemSelected(item);    
           }
    }


    @Override
    public void onUserItemClick(AdapterView<?> parent, View v, int position, long id, UserData user) 
    { 
        //wite your activity code here  

        Log.v("log", "name: " + user.getName());     
    }


    //tablistener
    class MyTabsListener implements ActionBar.TabListener 
    {
        public Fragment fragment;

        public MyTabsListener(Fragment fragment) 
        {
            this.fragment = fragment;
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) 
        {

        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) 
        {
            ft.replace(R.id.feedback_fragcontainer, fragment);
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) 
        {
            ft.remove(fragment);
        }

    }
}

Its xml-file:

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

        <LinearLayout
        android:id="@+id/feedback_fragcontainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" />

</LinearLayout>

And tab-fragment's xml:

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" 
    android:baselineAligned="false">

    <fragment
        android:id="@+id/feedbackuserListFragment"
        android:layout_width="match_parent"
        android:layout_weight="1"
        android:layout_height="match_parent"
        class="com.machinedata.ui.UserListFragment" >

    </fragment>

    <fragment
        android:id="@+id/feedbackSessionListFragment"
        android:layout_width="match_parent"
        android:layout_weight="1"
        android:layout_height="match_parent"
        class="com.machinedata.ui.feedback.SessionListFragment" >
        <!-- Preview: layout=@layout/details -->
    </fragment>

    <fragment
        android:id="@+id/feedbackDetailsFragment"
        android:layout_width="match_parent"
        android:layout_weight="0.5"
        android:layout_height="match_parent"
        class="com.machinedata.ui.feedback.DetailsFragment" >
        <!-- Preview: layout=@layout/details -->
    </fragment>




</LinearLayout>

To be honest, I'm not sure what the error message means with duplicate id, or what causes it. Basically I'm looking a solution to either create menu structure I described or way to fix my current implementation.

Upvotes: 1

Views: 261

Answers (1)

Tomas Žemaitis
Tomas Žemaitis

Reputation: 1907

Nested fragment functionality (implemented on API level 17) are provided in support package too. Extend your fragment from android.support.v4.app.Fragment instead of android.app.Fragment. And replace your parent activity to android.support.v4.app.FragmentActivity.

Upvotes: 1

Related Questions