0

我需要在我的应用程序中使用选项卡,因此我的代码基于此处的 Android FragmentTabs 示例。. 但是,我已经更改了代码中的几行以适合我自己的目的,如下所示。

在给定的 android 代码中,每次用户更改选项卡时,Fragment 都会被销毁,而 Fragment 会被创建。出于我的目的,这是不可取的。尽管我的 Fragments 可以彼此独立,但它们会对来自网络连接的实时数据做出反应并对其采取行动。仅仅因为 Fragment 不在视野范围内并不意味着我希望它停止在后台工作(遗憾的是,这似乎是 Android 示例中的思路)。因此,我将代码更改为“隐藏”和“显示”选项卡,而不是创建和销毁它们。

为了实现这一点,在示例代码中,我onTabChanged()在两个地方进行了更改,如下所示:

public void onTabChanged(String tabId) {
        TabInfo newTab = mTabs.get(tabId);
        if (mLastTab != newTab) {
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
            if (mLastTab != null) {
                if (mLastTab.fragment != null) {
                    ft.hide(mLastTab.fragment);  //***** 1st Alteration
                    //ft.detach(mLastTab.fragment);
                }
            }
            if (newTab != null) {
                if (newTab.fragment == null) {
                    newTab.fragment = Fragment.instantiate(mActivity,
                            newTab.clss.getName(), newTab.args);
                    ft.add(mContainerId, newTab.fragment, newTab.tag);
                } else {
                    ft.show(newTab.fragment);   //************ 2nd Alteration
                    //ft.attach(newTab.fragment);
                }
            }

            mLastTab = newTab;
            ft.commit();
            mActivity.getSupportFragmentManager().executePendingTransactions();
        }
    }

这现在可以按我的意愿工作。当设备重新定向时,问题就出现了。在第一次方向改变时,先前选择的选项卡内容即片段不显示。这与我“隐藏”和“显示”标签的事实有关。然而更严重的是,在设备第二次重新定向时会引发异常:

E/AndroidRuntime(371):引起:java.lang.NullPointerException E/AndroidRuntime(371):在 android.support.v4.app.FragmentManagerImpl.findFragmentByTag(FragmentManager.java:1211) E/AndroidRuntime(371):在 $ TabManager.addTab(ClassName.java:121)

addTab 方法在这里:

public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
        tabSpec.setContent(new DummyTabFactory(mActivity));
        String tag = tabSpec.getTag();

        TabInfo info = new TabInfo(tag, clss, args);

        // 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.
        FragmentManager fm = mActivity.getSupportFragmentManager();
        Log.i("Class Name","addTab() FragmentManager = " + fm.toString());
        Log.i("Class_Name","addTab() tag = " + tag);
        info.fragment = fm.findFragmentByTag(tag); // **** This causes the exception

        /*
         * Commented the following as Fragments are not removed but hidden/shown on tab change.
         */
        if (info.fragment != null && !info.fragment.isDetached()) {
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
            ft.detach(info.fragment);
            ft.commit();
        }

        mTabs.put(tag, info);
        mTabHost.addTab(tabSpec);
    }

更具体地说,在代码中可以看到异常抛出,info.fragment = fm.findFragmentByTag(tag);我试图准确地隔离什么对象是空的,即它是 FragmentManager 还是标签,但这些没有记录为空。

我不完全理解 Android 示例,如果我附加和分离片段而不是隐藏和显示它们,它可以正常工作。谁能解释问题是什么?

4

1 回答 1

1

根据运行时更改的 android 文档,当方向更改时,您的活动将重新启动。这意味着 FragmentManager 将其状态保存到一个包中,然后重新加载它。

所有已查看的选项卡都被添加,即使它们不可见,所以它们被隐藏在 FragmentManager 的添加片段列表中。但是,TabManager 不存储任何内容,它只是重新创建,我怀疑新的 TabManager 和恢复的 FragmentManager 之间的这种不匹配会影响您。

我建议仔细阅读该文档以及一些关于保存/恢复选项卡的非常慎重的选择。

其余的纯属猜测。看起来 Fragment.instantiate 和 ft.add 都没有检查新片段是否与旧片段重复。这可能会导致 TabManager 持有对一个片段的引用而 FragmentManager 持有该片段的两个实例的情况。

从 onCreate 中当前不可见的选项卡中清除 FragmentManager 可能就足够了,或者在创建新实例之前检查片段是否存在就足够了。

于 2012-05-25T13:24:04.300 回答