ActionBar Tab that contains fragments crashes when reshown

I have an SherlockFragmentActivity that uses an ActionBar with tabs. One of those tabs is an SherlockFragment that has a layout file that includes an fragment. When that tab is first shown, all is great. If I switch to another tab and then back to that tab, I get a crash:

02-21 10:25:10.077: E/AndroidRuntime(3916): Caused by: java.lang.IllegalArgumentException: Binary XML file line #29: Duplicate id 0x7f06006e, tag null, or parent id 0x0 with another fragment for com.nexapps.myq.fragments.TitleInfo 02-21 10:25:10.077: E/AndroidRuntime(3916): at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:275) 02-21 10:25:10.077: E/AndroidRuntime(3916): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676) 02-21 10:25:10.077: E/AndroidRuntime(3916): ... 21 more

My main activity:

public class TitleActivity extends SherlockFragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {       
        ...
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        ...
        Tab tab = actionBar.newTab().setText(R.string.details);
        tab.setTabListener(new TabListener<TitleDetailsFragment>(this, "details", TitleDetailsFragment.class));
        actionBar.addTab(tab);         
    }

}

Tab Listener: public class TabListener implements com.actionbarsherlock.app.ActionBar.TabListener { private Fragment mFragment; private final Activity mActivity; private final String mTag; private final Class mClass;

  public TabListener(Activity activity, String tag, Class<T> cls) {
      mActivity = activity;
      mTag = tag;
      mClass = cls;
  }

  public TabListener(Activity activity, String tag, Class<T> clz, Fragment fragment) {
      mActivity = activity;
      mTag = tag;
      mClass = clz;
      mFragment = fragment;
  }

  public void onTabSelected(Tab tab, FragmentTransaction ft) {
      if (mFragment == null) {
          mFragment = Fragment.instantiate(mActivity, mClass.getName());
          ft.add(android.R.id.content, mFragment, mTag);
      } else {
          ft.attach(mFragment);
      }

      TabChangeInterface tci = (TabChangeInterface) mActivity;
      if (tci != null) {
        tci.tabSelect(mTag);
      }
  }

  public void onTabUnselected(Tab tab, FragmentTransaction ft) {
      if (mFragment != null) {
          ft.detach(mFragment);
      }
  }

  public void onTabReselected(Tab tab, FragmentTransaction ft) {
  }

}

My Tab fragment:

public class TitleDetailsFragment extends SherlockFragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.activity_title, container, false);
        return view;
    }
}

R.layout.activity_title:

<fragment
   android:id="@+id/info"
   android:name="foo.TitleInfo"
   ...

I could remove the id (which fixes the issue) but those help with state changes. Any thoughts on how to keep the ids and fix the issue?


You cannot remove fragments that are embedded in an xml layout. For that, you should change your xml to include a <FrameLayout android:id="fragment_container" .../> and then programmatically replace the fragments in the frame by calling:

MyFrag newFragment = new MyFrag();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container,newFragment,"myFragName")
.addToBackStack("myFragName")//optional
.commit();

Assuming you are using support package, otherwise you just change getSupportFragmentManager() to getFragmentManager()

And you can read more about using fragments here: http://developer.android.com/training/basics/fragments/index.html

EDIT: Updated to include code based on new information

R.layout.activity_title:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Title" >

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

TitleActivity.class:

public class TitleActivity extends SherlockFragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {       
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_title);        
         ...
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        ...
        Tab tab = actionBar.newTab().setText(R.string.details);
        tab.setTabListener(new TabListener<TitleDetailsFragment>(this, "details", TitleDetailsFragment.class));
        actionBar.addTab(tab);         
    }

}

R.layout.details_fragment:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView1"
       android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal"
        android:textSize="10sp"
        android:textStyle="italic"
        android:text="Details are here!"/>
</RelativeLayout>

TabFragment:

public class TitleDetailsFragment extends SherlockFragment {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       return inflater.inflate(R.layout.details_fragment, container, false);
    }
}

TabListener you can keep the same as your code above.


So this has to do with the fact that tab contents are a fragment, and fragments can't contain fragments. So use views instead here or manually remove/add using transactions.

链接地址: http://www.djcxy.com/p/78914.html

上一篇: 将一个片段替换为可滑动TabHost中的另一个片段

下一篇: 包含片段的ActionBar选项卡在重新显示时崩溃