Android: дублирование фрагментов при использовании диспетчера поддержки фрагментов - PullRequest
12 голосов
/ 18 ноября 2011

У меня очень странная проблема с фрагментами.Я использую новейшую библиотеку поддержки.Я также использую код, аналогичный тому, который используется Google в их проекте IOSCHED

Но у меня проблема с воссозданием активности после ротации.После того, как действие уничтожено и создано снова, я вызываю методы для управления транзакцией фрагмента (в методе onStart).Эта строка вызывается только один раз, но она создает фрагмент ДВАЖДЫ!

Это мой метод активности:

public abstract class SinglePaneActivity extends FragmentActivity
{
    @Override
    protected void onStart()
    {
        super.onStart();

        if(mFragment == null)
        {
            mFragment = onCreatePane();     
            mFragment.setArguments(Utils.intentToFragmentArguments(getIntent()));

            Log.w(TAG, "Fragment creation counter = " + createCounter);
            createCounter++;

            getSupportFragmentManager() 
            .beginTransaction()
            .add(R.id.root_container,mFragment)
            .commit();
        }
    }

    @Override
    protected void onStop()
    {
        Log.i(TAG, "onStop");
        if(mFragment != null)
        {
            getSupportFragmentManager()
            .beginTransaction()
            .remove(mFragment)
            .commit();

            mFragment = null;
        }
        super.onStop();
    }
}

и мои журналы:

--Start of application--
11-18 13:26:37.050: I/SinglePaneActivity(19040): onCreate
11-18 13:26:37.050: I/SinglePaneActivity(19040): onStart
11-18 13:26:37.055: W/SinglePaneActivity(19040): replacing fragment, counter = 1
11-18 13:26:37.075: I/MyFragment(19040): onCreate
11-18 13:26:37.110: I/MyFragment(19040): onActivityCreated
--Rotating the device--
11-18 13:26:39.600: I/SinglePaneActivity(19040): onStop
11-18 13:26:39.600: I/SinglePaneActivity(19040): onDestroy
11-18 13:26:39.605: I/MyFragment(19040): onDestroy
11-18 13:26:39.755: I/MyFragment(19040): onCreate
11-18 13:26:39.755: I/SinglePaneActivity(19040): onCreate
11-18 13:26:39.790: I/MyFragment(19040): onActivityCreated
11-18 13:26:39.800: I/SinglePaneActivity(19040): onStart
11-18 13:26:39.800: W/SinglePaneActivity(19040): replacing fragment, counter = 2
11-18 13:26:39.810: I/MyFragment(19040): onCreate
11-18 13:26:39.815: I/MyFragment(19040): onActivityCreated
--Rotating the device back--
11-18 13:36:47.060: I/SinglePaneActivity(19040): onStop
11-18 13:36:47.060: I/SinglePaneActivity(19040): onDestroy
11-18 13:36:47.060: I/MyFragment(19040): onDestroy
11-18 13:36:47.065: I/MyFragment(19040): onDestroy
11-18 13:36:47.130: I/MyFragment(19040): onCreate
11-18 13:36:47.130: I/MyFragment(19040): onCreate
11-18 13:36:47.130: I/SinglePaneActivity(19040): onCreate
11-18 13:36:47.140: I/MyFragment(19040): onActivityCreated
11-18 13:36:47.150: I/MyFragment(19040): onActivityCreated
11-18 13:36:47.150: I/SinglePaneActivity(19040): onStart
11-18 13:36:47.150: W/SinglePaneActivity(19040): replacing fragment, counter = 3
11-18 13:36:47.160: I/MyFragment(19040): onCreate
11-18 13:36:47.160: I/MyFragment(19040): onActivityCreated
--Exiting the app--
11-18 13:36:48.880: I/SinglePaneActivity(19040): onStop
11-18 13:36:48.885: I/SinglePaneActivity(19040): onDestroy
11-18 13:36:48.885: I/MyFragment(19040): onDestroy
11-18 13:36:48.890: I/MyFragment(19040): onDestroy
11-18 13:36:48.890: I/MyFragment(19040): onDestroy

Так чточисло фрагментов увеличивается после каждого поворота.

После поворота он восстанавливает фрагмент перед тем, как перейти к моему методу onStart, а мой метод onStart создает второй такой же фрагмент в том же контейнере макета Frame.Но ГДЕ это восстанавливает первый фрагмент?Я хочу это запретить.Или я должен изменить свое «если», чтобы проверить, создано ли оно уже?Но я не знаю, как это определить.Похоже, что нулевой тест бесполезен.

Я также сделал небольшой обходной путь, заменив метод add() на replace().После этого количество фрагментов не увеличивается, и каждый фрагмент уничтожается до того, как новый будет создан в методе onStart.Но это создает серьезную проблему в некоторых фрагментах, где я запускаю некоторые фоновые процессы в их методе onCreate ...

Пожалуйста, помогите мне ... Я действительно понятия не имею, что с этим делать.Большое спасибо за любой совет или идею!

Ответы [ 3 ]

24 голосов
/ 21 ноября 2011

Ну, я нашел решение.Мне пришлось переместить код с помощью диспетчера фрагментов из onStart в onCreate и проверить null значение savedInstanceState.Ну, я не знал, что он автоматически сохраняется из savedInstanceState.Полезно знать!

РЕДАКТИРОВАТЬ: И чтобы сделать это полностью правильно, то есть восстановить фрагмент, когда saveInstanceState не нуль, должно быть:

    if(savedInstanceState == null)
    {
        mFragment = onCreatePane();     
        mFragment.setArguments(Utils.intentToFragmentArguments(getIntent()));

        getSupportFragmentManager() 
        .beginTransaction()
        .add(R.id.root_container,mFragment)
        .commit();
    } 
    else
    {
        mFragment = getSupportFragmentManager().findFragmentById(R.id.root_container);
    }
1 голос
/ 17 сентября 2014

У меня была похожая проблема, но я добавлял дочерний фрагмент из родительского фрагмента и видел дублированный дочерний фрагмент. Я пытался добавить его в onStart родительского фрагмента, чтобы получить доступ к родительскому представлению, которое недоступно в onCreate. Поэтому вместо того, чтобы перемещать код в onCreate, я переместил его в onActivityCreated; этот метод имеет доступ к родительскому представлению, а также имеет доступ к переменной savedInstanceState для проверки того, что фрагмент уже добавляется автоматически. Это не проблема при добавлении фрагмента из действия, потому что представление действия доступно в onCreate.


Если по какой-то причине вам нужно добавить фрагмент в onStart или другое место, где savedInstanceState недоступен, вот альтернатива. Используя оригинальный код onStart из вопроса ...

   if(mFragment == null)
    {
        mFragment = onCreatePane();     
        mFragment.setArguments(Utils.intentToFragmentArguments(getIntent()));

        Log.w(TAG, "Fragment creation counter = " + createCounter);
        createCounter++;

        getSupportFragmentManager() 
        .beginTransaction()
        .add(R.id.root_container,mFragment)
        .commit();
    }

... вы могли бы replace вместо add фрагмента:

   if(mFragment == null)
    {
        mFragment = onCreatePane();     
        mFragment.setArguments(Utils.intentToFragmentArguments(getIntent()));

        Log.w(TAG, "Fragment creation counter = " + createCounter);
        createCounter++;
    }

    getSupportFragmentManager() 
    .beginTransaction()
    .replace(R.id.root_container,mFragment)
    .commit();

Тогда, если фрагмент уже был добавлен автоматически, ваш новый фрагмент просто заменит его в представлении.

0 голосов
/ 04 апреля 2012

Или, если ваш фрагмент не в заднем стеке: setRetainInstance(true);

...