Android 当方向更改时,使用选项卡重新加载活动时,片段会初始化两次
当我更改设备的方向时,重新加载带有选项卡和片段的活动时出现问题 情况如下: 我有一个活动,在操作栏中有3个选项卡。每个选项卡在主视图的Android 当方向更改时,使用选项卡重新加载活动时,片段会初始化两次,android,tabs,android-fragments,device-orientation,Android,Tabs,Android Fragments,Device Orientation,当我更改设备的方向时,重新加载带有选项卡和片段的活动时出现问题 情况如下: 我有一个活动,在操作栏中有3个选项卡。每个选项卡在主视图的FrameLayout中加载不同的片段。如果我不改变设备的方向,一切正常。但当我这样做时,Android会尝试两次初始化当前选定的片段,这会产生以下错误: E/AndroidRuntime(2022): Caused by: android.view.InflateException: Binary XML file line #39: Error inflati
FrameLayout
中加载不同的片段。如果我不改变设备的方向,一切正常。但当我这样做时,Android会尝试两次初始化当前选定的片段,这会产生以下错误:
E/AndroidRuntime(2022): Caused by: android.view.InflateException: Binary XML file line #39: Error inflating class fragment
以下是产生错误的步骤顺序:
Activity.onCreate()中,我将第一个选项卡添加到操作栏中。当我这样做时,该选项卡将自动被选中。这可能是未来的一个问题,但我现在不介意<调用code>onTabSelected
,创建并加载第一个片段的新实例(请参见下面的代码)ActionBar。选择Tab(myTab)
以选择Tab nr 2ontabonselected()
,第二个选项卡调用onTabSelected()
。此序列替换片段2实例的当前片段(参见下面的代码)Fragment.onCreateView()
,片段布局膨胀onCreate()
,然后调用onCreateView()
,这会在我尝试(第二次)膨胀布局时产生异常android:configChanges
技巧的情况下实现这一点
如果还不清楚,我想知道的是如何防止片段的重新生成,还是避免它的双重初始化。很高兴知道为什么会发生这种情况P
以下是相关代码:
公共类MyActivity扩展活动实现ActionBar.TabListener{
私有静态最终字符串标记\u FRAGMENT\u 1=“frag1”;
私有静态最终字符串标记\u FRAGMENT\u 2=“frag2”;
私有静态最终字符串标记\u FRAGMENT\u 3=“frag3”;
片段frag1;
片段frag2;
片段frag3;
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//my_布局中包含一个碎片布局
setContentView(R.layout.my_layout);
//获取对Android自动创建的片段的引用
//重新加载活动时
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\u FRAGMENT\u 3)
ActionBar ActionBar=getActionBar();
//剪断。。。
//这将触发为第一个选项卡选择的选项
actionBar.addTab(actionBar.newTab()
.setText(“Tab1”).setTabListener(本)
.setTag(MyActivity.TAG_FRAGMENT_1));
actionBar.addTab(actionBar.newTab()
.setText(“Tab2”).setTabListener(本)
.setTag(MyActivity.TAG_FRAGMENT_2));
actionBar.addTab(actionBar.newTab()
.setText(“Tab3”).setTabListener(本)
.setTag(MyActivity.TAG_FRAGMENT_3));
Tab t=null;
//这里我得到了一个必须选择的标签的引用
//剪断。。。
//这将触发onTabUnselected/onTabSelected
ab.selectTab(t);
}
@凌驾
受保护的空onDestroy(){
//不确定这是否必要
this.frag1=null;
this.frag2=null;
this.frag3=null;
super.ondestory();
}
@凌驾
已选择的公共事务(选项卡,碎片事务处理ft){
Fragment curFrag=getFragmentInstanceForTag(tab.getTag().toString());
如果(curFrag==null){
curFrag=createFragmentInstanceForTag(tab.getTag().toString());
如果(curFrag==null){
//剪断。。。
返回;
}
}
ft.replace(R.id.fragment_容器,curFrag,tab.getTag().toString());
}
@凌驾
已选择公共空页(选项卡,碎片事务ft)
{
Fragment curFrag=getFragmentInstanceForTag(tab.getTag().toString());
如果(curFrag==null){
//剪断。。。
返回;
}
ft.remove(curFrag);
}
私有片段getFragmentInstanceForTag(字符串标记)
{
//返回this.frag1、this.frag2或this.frag3
//取决于作为参数传递的标记
}
私有片段createFragmentInstanceForTag(字符串标记)
{
//返回标记请求的片段的新实例
//并将其分配给this.frag1、this.frag2或this.frag3
}
}
片段的代码是无关的,它只是在
onCreateView()
方法覆盖上返回一个膨胀的视图。当屏幕旋转并且应用程序重新启动时,它似乎通过调用defaul来重新创建每个片段
FragmentTransition ft = getSupportFragmentManager().begin();
ft.detach(myFragment);
ft.commit();
if (mView != null) {
// Log.w(TAG, "Fragment initialized again");
((ViewGroup) mView.getParent()).removeView(mView);
return mView;
}
// normal onCreateView
mView = inflater.inflate(R.layout...)
private WeakReference<View> mRootView;
private LayoutInflater mInflater;
/**
* inflate the fragment layout , or use a previous one if already stored <br/>
* WARNING: do not use in any function other than onCreateView
* */
private View inflateRootView() {
View rootView = mRootView == null ? null : mRootView.get();
if (rootView != null) {
final ViewParent parent = rootView.getParent();
if (parent != null && parent instanceof ViewGroup)
((ViewGroup) parent).removeView(rootView);
return rootView;
}
rootView = mFadingHelper.createView(mInflater);
mRootView = new WeakReference<View>(rootView);
return rootView;
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
mInflater=inflater!=null?inflater:LayoutInflater.from(getActivity());
final View view = inflateRootView();
... //update your data on the views if needed
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
setRetainInstance(true);
}
android:configChanges="keyboardHidden|orientation|screenSize"
private void loadFragment(){
LogUtil.l(TAG,"loadFragment",true);
fm = getSupportFragmentManager();
Fragment hf = fm.findFragmentByTag("HOME");
Fragment sf = fm.findFragmentByTag("SETTING");
if(hf==null) {
homeFragment = getHomeFragment();// new HomeFragment();
settingsFragment = getSettingsFragment();// new Fragment();
fm.beginTransaction().add(R.id.fm_place, settingsFragment, "SETTING").hide(settingsFragment).commit();
fm.beginTransaction().add(R.id.fm_place, homeFragment, "HOME").commit();
activeFragment = homeFragment;
}else{
homeFragment = hf;
settingsFragment = sf;
activeFragment = sf;
}
}