Android嵌套片段-java.lang.IllegalStateException:活动已被销毁

Android嵌套片段-java.lang.IllegalStateException:活动已被销毁,android,android-fragments,Android,Android Fragments,我正在尝试使用FragmentTabHost创建选项卡式布局。一切正常,但后来我意识到我想在一个选项卡中切换多个片段 在看到几个嵌套片段的示例后,我实现了下面的类,一方面它应该成为添加到选项卡主机的单个片段,另一方面它是选项卡内容的父片段: /** * Instances of this class are used as a containers for fragments inside app's tabs. * * The reason for using this intermed

我正在尝试使用FragmentTabHost创建选项卡式布局。一切正常,但后来我意识到我想在一个选项卡中切换多个片段

在看到几个嵌套片段的示例后,我实现了下面的类,一方面它应该成为添加到选项卡主机的单个片段,另一方面它是选项卡内容的父片段:

/**
 * Instances of this class are used as a containers for fragments inside app's tabs.
 *
 * The reason for using this intermediate class is that we need to switch multiple fragments
 * in a single tab. Since each tab is supposed to hold just a single fragment, this container will
 * be that fragment. The actual switching of fragments then happens here and not in app's tab.
 */
public class FragmentContainer extends Fragment {

    public static final String PARAM_CONTENT_FRAGMENT = "param_content_fragment";

    public static final String EXTRA_DEFAULT_FRAGMENT = "default_fragment";


    public static FragmentContainer newInstance(String class_name) {
        FragmentContainer container = new FragmentContainer();

        Bundle bundle = new Bundle(1);
        bundle.putString(EXTRA_DEFAULT_FRAGMENT, class_name);
        container.setArguments(bundle);

        return container;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_container, null);
    }

    @Override
    public void onResume() {
        super.onResume();
        Fragment f = getChildFragmentManager().findFragmentById(R.id.fragment_content);
        if (f == null) {
            Class<? extends Fragment> claz = (Class<? extends Fragment>) getArguments().getSerializable(
                    PARAM_CONTENT_FRAGMENT);
            FragmentTransaction tx = getChildFragmentManager().beginTransaction();
            try {
                f = claz.newInstance();
                f.setTargetFragment(this, 0);
                tx.add(R.id.fragment_content, f);
                tx.commit();
                getChildFragmentManager().executePendingTransactions();
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }

        }
    }

    @Override
    public void onDetach() {
        super.onDetach();

        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);

        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }


    public void replaceContent(Class<? extends Fragment> claz, Bundle args) {
        FragmentTransaction tx = getChildFragmentManager().beginTransaction();

        tx.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

        // save
        Fragment curFrag = getChildFragmentManager().findFragmentById(R.id.fragment_content);
        if (curFrag != null) {
            tx.addToBackStack(curFrag.getClass().getSimpleName());
        }

        // change
        try {
            Fragment newFragment = claz.newInstance();
            newFragment.setArguments(args);
            tx.replace(R.id.fragment_content, newFragment, claz.getClass().getSimpleName());
            tx.commit();
            getChildFragmentManager().executePendingTransactions();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // Suppress "unchecked" warning. claz variable is checked for compatibility with Fragment class
    // inside the surrounding "if" statement
    @SuppressWarnings("unchecked")

    public void setDefaultContent(Bundle args) {

        Class<?> claz = null;

        try {
            claz = Class.forName(getArguments().getString(EXTRA_DEFAULT_FRAGMENT));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // Ensure that claz extends Fragment
        if (claz != null && Fragment.class.isAssignableFrom(claz) ) {
            Fragment childFragment = getChildFragmentManager().findFragmentById(R.id.fragment_content);
            // Replace the content if the currently showed fragment is not the default
            if (!claz.isInstance(childFragment)) {
                replaceContent((Class<? extends Fragment>) claz, args);
            }
        } else {
            Log.e("FragmentContainer/setDefaultContent", "default class is either null or does" +
                    "not extend Fragment");
        }
    }


}
当我启动应用程序时,tx.commit立即出现异常;从replaceContent中调用,以显示第一个选项卡的默认片段

在构建这个结构时,我当然忽略了Android系统的一些限制活动->FragmentTabHost->FragmentContainer->Fragments,或者,可能误用了其中一个API,但我就是找不到它


任何帮助都将不胜感激。

终于找到了:我打电话给newTab.mfFragmentContainer.setDefaultContentnull;在提交添加的newTab.mFragmentContainer并确保其已执行之前。换句话说,在将ContainerFragment正确添加到视图层次结构之前,我正在操作它

    private void initializeTabHost(Bundle args) {
        mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);
        TabInfo tabInfo = null;
        Main.addTab(this, mTabHost,
                mTabHost.newTabSpec(HOME_TAB_TAG).setIndicator(getString(R.string.home_tab_indicator)),
                (tabInfo = new TabInfo(HOME_TAB_TAG, HomeFragment.class, args)));
        mMapTabInfo.put(tabInfo.mTag, tabInfo);

        // Default to home tab
        this.onTabChanged(HOME_TAB_TAG);

        mTabHost.setOnTabChangedListener(this);
    }

    private static void addTab(Main activity, FragmentTabHost tabHost, TabHost.TabSpec tabSpec, TabInfo tabInfo) {
        // Attach a Tab view factory to the spec
        tabSpec.setContent(activity.new TabFactory(activity));
        String tag = tabSpec.getTag();

        // Check to see if we already have a fragment for this tab, probably
        // from a previously saved state.  If so, deactivate it, because our
        // initial state is that a tab isn't shown.
        tabInfo.mFragmentContainer = (FragmentContainer) activity.getSupportFragmentManager().findFragmentByTag(tag);
        if (tabInfo.mFragmentContainer != null && !tabInfo.mFragmentContainer.isDetached()) {
            FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
            ft.detach(tabInfo.mFragmentContainer);
            ft.commit();
            activity.getSupportFragmentManager().executePendingTransactions();
        }

        tabHost.addTab(tabSpec, tabInfo.mClass, null);
    }

    @Override
    public void onTabChanged(String tag) {
        TabInfo newTab = (TabInfo) this.mMapTabInfo.get(tag);
        if (mLastTab != newTab) {
            FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
            if (mLastTab != null) {
                if (mLastTab.mFragmentContainer != null) {
                    ft.detach(mLastTab.mFragmentContainer);
                }
            }
            if (newTab != null) {
                if (newTab.mFragmentContainer == null) {
                    newTab.mFragmentContainer = FragmentContainer.newInstance(newTab.mClass.getName());
                    ft.add(android.R.id.tabcontent, newTab.mFragmentContainer, newTab.mTag);
                } else {
                    ft.attach(newTab.mFragmentContainer);
                }
                newTab.mFragmentContainer.setDefaultContent(null);
            }

            mLastTab = newTab;
            ft.commit();
            this.getSupportFragmentManager().executePendingTransactions();

        } else {
            newTab.mFragmentContainer.setDefaultContent(null);
        }
    }