Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/233.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 当方向更改时,使用选项卡重新加载活动时,片段会初始化两次_Android_Tabs_Android Fragments_Device Orientation - Fatal编程技术网

Android 当方向更改时,使用选项卡重新加载活动时,片段会初始化两次

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

当我更改设备的方向时,重新加载带有选项卡和片段的活动时出现问题

情况如下:

我有一个活动,在操作栏中有3个选项卡。每个选项卡在主视图的
FrameLayout
中加载不同的片段。如果我不改变设备的方向,一切正常。但当我这样做时,Android会尝试两次初始化当前选定的片段,这会产生以下错误:

E/AndroidRuntime(2022): Caused by: android.view.InflateException: Binary XML file line #39: Error inflating class fragment
以下是产生错误的步骤顺序:

  • 我加载活动,选择选项卡2。并更改设备的方向
  • Android会销毁tab nr 2(从现在起,“fragment 2”)加载的活动和片段实例。然后继续创建活动和片段的新实例
  • Activity.onCreate()中,我将第一个选项卡添加到操作栏中。当我这样做时,该选项卡将自动被选中。这可能是未来的一个问题,但我现在不介意<调用code>onTabSelected
    ,创建并加载第一个片段的新实例(请参见下面的代码)
  • 我添加了所有其他选项卡,没有触发任何事件,这很好
  • 我调用
    ActionBar。选择Tab(myTab)
    以选择Tab nr 2
  • 第一个选项卡调用
    ontabonselected()
    ,第二个选项卡调用
    onTabSelected()
    。此序列替换片段2实例的当前片段(参见下面的代码)
  • 接下来,对Fragment 2实例调用
    Fragment.onCreateView()
    ,片段布局膨胀
  • 问题就在这里。Android再次调用片段实例上的
    onCreate()
    ,然后调用
    onCreateView()
    ,这会在我尝试(第二次)膨胀布局时产生异常
  • 很明显,问题是Android两次初始化这个片段,但我不知道为什么

    我尝试在重新加载活动时不选择第二个选项卡,但第二个片段仍然被初始化,并且没有显示(因为我没有选择它的选项卡)

    我发现这个问题:

    用户的提问与我基本相同,但我不喜欢选择的答案(这只是一种变通方法)。必须有某种方法可以在不使用
    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;
         }
     }