Фрагмент инициализируется дважды при перезагрузке активности с вкладками при изменении ориентации

У меня проблема с перезагрузкой активности с вкладками и фрагментами, когда я меняю ориентацию своего устройства.

Вот ситуация:

У меня есть активность, которая имеет 3 вкладки на панели действий. Каждая вкладка загружает отдельный фрагмент в FrameLayoutв главном представлении. Все работает нормально, если я не меняю ориентацию устройства. Но когда я делаю это, Android дважды пытается инициализировать текущий выбранный фрагмент, что приводит к следующей ошибке:

E/AndroidRuntime(2022): Caused by: android.view.InflateException: Binary XML file line #39: Error inflating class fragment

Вот последовательность шагов, которые приводят к ошибке:

  1. Я загружаю активность, выбираю вкладку № 2 и меняю ориентацию устройства.
  2. Android уничтожает активность и экземпляр фрагмента, загруженного вкладкой № 2 (с этого момента, «Фрагмент 2» ). Затем он переходит к созданию новых экземпляров действия и фрагмента.
  3. Внутри Activity.onCreate()я добавляю первую вкладку на панель действий. Когда я это делаю, эта вкладка автоматически выбирается. Это может стать проблемой в будущем, но сейчас я не возражаю против этого. onTabSelectedвызывается, и создается и загружается новый экземпляр первого фрагмента (см. код ниже ).
  4. Я добавляю все остальные вкладки без запуска каких-либо событий, и это нормально.
  5. Я звоню ActionBar.selectTab(myTab), чтобы выбрать вкладку № 2.
  6. onTabUnselected()вызывается для первой вкладки, а затем onTabSelected()для второй вкладки. Эта последовательность заменяет текущий фрагмент экземпляром фрагмента 2 (, см. код ниже ).
  7. Затем вызывается Fragment.onCreateView()для экземпляра Фрагмента 2, и макет фрагмента увеличивается.
  8. Вот в чем проблема. Android вызывает onCreate(), а затем onCreateView()для экземпляра фрагмента ЕЩЕ РАЗ,который создает исключение, когда я пытаюсь раздуть (второй раз )макет.

Очевидно, проблема в том, что Android дважды инициализирует фрагмент, но я не знаю, почему.

Я пробовал НЕ выбирать вторую вкладку при перезагрузке действия, но второй фрагмент все равно инициализируется и не отображается (, так как я не выбрал его вкладку ).

Я нашел этот вопрос:Фрагменты Android воссозданы при изменении ориентации

Пользователь спрашивает в основном то же, что и я, но мне не нравится выбранный ответ (это всего лишь обходной путь ). Должен быть какой-то способ заставить это работать без трюка android:configChanges.

В случае, если не ясно, что я хочу знать, как предотвратить воссоздание фрагмента или избежать его двойной инициализации. Было бы неплохо узнать, почему так происходит. :П

Вот соответствующий код:

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().

18
задан Community 23 May 2017 в 11:53
поделиться