【发布时间】:2012-06-25 16:03:23
【问题描述】:
当我更改设备的方向时,我在重新加载带有选项卡和片段的活动时遇到问题。
情况如下:
我有一个在操作栏中有 3 个选项卡的活动。每个选项卡在主视图的FrameLayout 中加载不同的片段。如果我不改变设备的方向,一切正常。但是当我这样做时,Android 会尝试初始化当前选择的片段两次,这会产生以下错误:
E/AndroidRuntime(2022): Caused by: android.view.InflateException: Binary XML file line #39: Error inflating class fragment
以下是产生错误的步骤顺序:
- 我加载活动,选择选项卡 nr 2. 并更改设备的方向。
- Android 会销毁由选项卡 nr 2 加载的片段的活动和实例(从现在开始,“片段 2”)。然后它继续创建 Activity 和 Fragment 的新实例。
- 在
Activity.onCreate()内部,我将第一个选项卡添加到操作栏。当我这样做时,此选项卡会自动选择。它可能代表未来的问题,但我现在不介意。调用onTabSelected并创建并加载第一个片段的新实例(参见下面的代码)。 - 我添加了所有其他选项卡而没有触发任何事件,这很好。
- 我致电
ActionBar.selectTab(myTab)选择 Tab nr 2。 -
第一个选项卡调用
onTabUnselected(),然后第二个选项卡调用onTabSelected()。此序列替换片段 2 实例的当前片段(参见下面的代码)。 - 接下来,在 Fragment 2 实例上调用
Fragment.onCreateView(),并且片段布局得到扩展。 - 这就是问题所在。 Android 在片段实例 ONCE AGAIN 上调用
onCreate()然后onCreateView(),当我尝试扩展(第二次)布局时会产生异常。
显然问题是 Android 两次初始化片段,但我不知道为什么。
我尝试在重新加载活动时不选择第二个选项卡,但第二个片段无论如何都会被初始化并且它没有显示(因为我没有选择它的选项卡)。
我发现了这个问题:Android Fragments recreated on orientation change
用户问的问题基本上和我一样,但我不喜欢选择的答案(这只是一种解决方法)。必须有某种方法可以在不使用 android:configChanges 技巧的情况下使其正常工作。
如果不清楚,我想知道如何阻止片段的重新创建或避免片段的双重初始化。很高兴知道为什么会发生这种情况。 :P
以下是相关代码:
public class MyActivity extends Activity implements ActionBar.TabListener {
private static final String TAG_FRAGMENT_1 = "frag1";
private static final String TAG_FRAGMENT_2 = "frag2";
private static final String TAG_FRAGMENT_3 = "frag3";
Fragment frag1;
Fragment frag2;
Fragment frag3;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// my_layout contains a FragmentLayout inside
setContentView(R.layout.my_layout);
// Get a reference to the fragments created automatically by Android
// when reloading the activity
FragmentManager fm = getFragmentManager();
this.frag1 = fm.findFragmentByTag(MyActivity.TAG_FRAGMENT_1);
this.frag2 = fm.findFragmentByTag(MyActivity.TAG_FRAGMENT_2);
this.frag3 = fm.findFragmentByTag(MyActivity.TAG_FRAGMENT_3)
ActionBar actionBar = getActionBar();
// snip...
// This triggers onTabSelected for the first tab
actionBar.addTab(actionBar.newTab()
.setText("Tab1").setTabListener(this)
.setTag(MyActivity.TAG_FRAGMENT_1));
actionBar.addTab(actionBar.newTab()
.setText("Tab2").setTabListener(this)
.setTag(MyActivity.TAG_FRAGMENT_2));
actionBar.addTab(actionBar.newTab()
.setText("Tab3").setTabListener(this)
.setTag(MyActivity.TAG_FRAGMENT_3));
Tab t = null;
// here I get a reference to the tab that must be selected
// snip...
// This triggers onTabUnselected/onTabSelected
ab.selectTab(t);
}
@Override
protected void onDestroy() {
// Not sure if this is necessary
this.frag1 = null;
this.frag2 = null;
this.frag3 = null;
super.onDestroy();
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Fragment curFrag = getFragmentInstanceForTag(tab.getTag().toString());
if (curFrag == null) {
curFrag = createFragmentInstanceForTag(tab.getTag().toString());
if(curFrag == null) {
// snip...
return;
}
}
ft.replace(R.id.fragment_container, curFrag, tab.getTag().toString());
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
Fragment curFrag = getFragmentInstanceForTag(tab.getTag().toString());
if (curFrag == null) {
// snip...
return;
}
ft.remove(curFrag);
}
private Fragment getFragmentInstanceForTag(String tag)
{
// Returns this.frag1, this.frag2 or this.frag3
// depending on which tag was passed as parameter
}
private Fragment createFragmentInstanceForTag(String tag)
{
// Returns a new instance of the fragment requested by tag
// and assigns it to this.frag1, this.frag2 or this.frag3
}
}
片段的代码无关紧要,它只是在onCreateView() 方法覆盖上返回一个膨胀的视图。
【问题讨论】:
-
只是一个建议...如果您缩小帖子的大小,您更有可能得到答案:P。尽管我当然很欣赏您包含的详细信息...我建议您包含一些易于阅读并吸引人们注意力的摘要(在您的帖子开头的某个地方)。
-
另外,使用
inline code、粗体(但不要太多),甚至 html 标题 () 都可以帮助组织您的帖子。 ..但不要滥用它太多:P -
需要一些代码,最好是
onTabSelected和onTabUnselected方法 -
感谢您的建议。我考虑了帖子的长度,但我想尽可能详细地说明,因为除了最后一部分之外,一切似乎都运行良好。
标签: android tabs android-fragments device-orientation