我需要在我的应用程序中使用Tabs,因此我的代码基于Android FragmentTabs示例here.。但是我在代码中更改了几行以符合我自己的目的,如下所示。
在给定的android代码中,每次用户更改选项卡时,Fragment的视图外部都会被破坏,并且会创建进入视图的Fragment。出于我的目的,这是不可取的。虽然我的片段可以彼此独立,但它们会对通过网络连接传输的实时数据做出反应并对其进行操作。仅仅因为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);
抛出的。在代码中可以看出我试图准确地隔离什么对象是null,即它是FragmentManager还是标签但是这些都没有记录为null
我不完全理解Android示例,如果我附加和分离碎片而不是隐藏和显示它们,它可以正常工作。任何人都可以解释问题是什么吗?
答案 0 :(得分:1)
根据the android docs on runtime changes,当方向发生变化时,您的活动会重新启动。这意味着FragmentManager将其状态保存到一个包中然后重新加载它。
添加了所有已查看的选项卡,即使它们不可见,因此它们会在FragmentManager的添加片段列表中被隐藏起来。 TabManager不存储任何东西,但它只是重新创建,我怀疑新TabManager和恢复的FragmentManager之间的这种不匹配正在向你发送。
我建议您仔细阅读that doco以及有关保存/恢复标签的一些非常谨慎的选择。
剩下的就是纯粹的猜测。看起来Fragment.instantiate和ft.add看起来都没有检查新片段是否与旧片段重复。这可能会导致TabManager保存对一个片段的引用,而FragmentManager包含该片段的两个实例。
从onCreate中当前不可见的选项卡中清除FragmentManager或在创建新实例之前检查片段是否存在就足够了。