Сохранить объект фрагмента при вращении - PullRequest
48 голосов
/ 02 марта 2011

Я разработал приложение в Honeycomb и использую фрагменты.
Это мое приложение

  • У меня есть Activity (скажем, A1), и в нем есть фрагмент
  • Первоначально этот фрагмент содержит объект, один объект фрагмента, скажем (F1)
  • Затем, в зависимости от действий пользователя, он может измениться на другие объекты F2, F3 ....

В чем моя проблема

Когда пользователь поворачивает устройство, воссоздается действие, в результате чего F1 становится объектом фрагмента, хотя до его поворота это не было
What is the way to retain the fragment object while rotating?
Я использовал setRetainInstance(true);, но у меня это не сработало
И я добавил фрагмент по коду в мою onCreate функцию, подобную этой

@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);

   FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();

   Fragment homeFragment = new Home();
   fragmentTransaction.add(R.id.mainFragement, homeFragment);
   fragmentTransaction.commit();
}

Ответы [ 6 ]

62 голосов
/ 02 марта 2011

По умолчанию Android сохранит фрагменты объектов.В вашем коде вы устанавливаете homeFragment в вашей функции onCreate.Вот почему всегда homeFragment или fl то, что вы задали в onCreate.

Поскольку всякий раз, когда вы вращаетесь, onCreate будет выполняться и устанавливать ваш фрагментный объект на первыйone

Поэтому простое решение для вас - проверить, является ли savedInstanceState bundle нулевым или нет, и установить объект фрагмента

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if(null == savedInstanceState) {
        // set you initial fragment object 
    }
 }
38 голосов
/ 02 ноября 2012

Вам нужно присвоить вашему Фрагменту уникальный тег и проверить, уже добавлен ли этот Фрагмент к вашей Деятельности.

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    String tag = "my_fragment";
    FragmentManager fragmentManager = getFragmentManager();
    if(fragmentManager.findFragmentByTag(tag) == null) {
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        Fragment homeFragment = new Home();
        fragmentTransaction.add(R.id.mainFragement, homeFragment, tag);
        fragmentTransaction.commit();
    }
}

Проверка того, является ли savedInstanceState ноль, не является безопасным способом проверки того, установлен ли уже ваш фрагмент - он будет работать в большинстве случаев, но в некоторых случаях (например, когда устройство не хватает памяти) Android может убить ваша активность, которая может сломать ваше приложение.

Чтобы увидеть это в действии, установите флажок «Не выполнять действия» в параметрах разработки устройства (параметр доступен в Android 4.0+, не уверен в более ранних версиях). Когда вы открываете новое действие, ваше первое действие уничтожается. Когда вы вернетесь к нему (нажав назад), он будет создан снова, а для элемента saveInstanceState установлено значение , а не null. Тем не менее, ваш фрагмент больше не находится в активности, и вы должны добавить его снова.

РЕДАКТИРОВАТЬ - Показывает оригинальный принцип, но с SupportFragmentManager

public class ActivityAwesome extends AppCompatActivity
{
    private final String TAG = getClass().getSimpleName();
    private FragmentHome mHomeFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_layout);

        FragmentManager fragmentManager = getSupportFragmentManager();
        Fragment fragment = fragmentManager.findFragmentByTag(TAG);
        if(fragment == null)
        {
            // Create the detail fragment and add it to the activity using a fragment transaction.
            mHomeFragment = new FragmentHome();
            fragmentManager.beginTransaction()
                    .add(R.id.fragment_container, mHomeFragment, TAG)
                    .commit();
        }
        else
        {
            // get our old fragment back !
            mHomeFragment = (FragmentHome)fragment;
        }
    }
}

это особенно полезно, если вы хотите манипулировать фрагментом (в данном случае mHomeFragment) после вращения устройства

3 голосов
/ 26 января 2015

Используйте onAttachFragment() в вашем Activity для переназначения объекта:

@Override
public void onAttachFragment(Fragment fragment) {
    if (fragment instanceof MyFragment)
        this.myFragment = (MyFragment) fragment;
}
0 голосов
/ 14 апреля 2019

просто измените @Ralf ответ, чтобы он был более динамичным, не нужно указывать определенный фрагмент для сохранения, но в случае, если вы захотите указать, это также возможно:

 public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //set Home/Main/default fragment
        changeFragmentTo(HomeFragment.newInstance(), FRAGMENT_TAG_HOME_FRAGMENT);


        if (getCurrentFragment() != null) {
            //if screen rotated retain Fragment
            changeFragmentTo(getCurrentFragment(), getCurrentFragment().getTag());

        }

    }


    private Fragment getCurrentFragment() {
//fl_main_container is FarmeLayout where I load my Fragments
        return getSupportFragmentManager().findFragmentById(R.id
                .fl_main_container);
    }



    /**
     * changeFragmentTo(Fragment fragmentToLoad, String fragmentTag)
     *
     * @param fragmentToLoad : dataType > v4.app.Fragment :: the object of the fragment you want to load in form of MyFragment() or MyFragment().newInstance()
     * @param fragmentTag    :  dataType > String :: a String which identify the "tag" of the fragment in form of "FRAGMENT_TAG_MY_FRAGMENT", Value must be stored in {@link models.MyConstants}
     */


    public void changeFragmentTo(Fragment fragmentToLoad, String fragmentTag) {

        if (getSupportFragmentManager().findFragmentByTag(fragmentTag) == null) {
            getSupportFragmentManager()
                    .beginTransaction()
                    .replace(R.id.fl_main_container, fragmentToLoad, fragmentTag)
                    .setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                    .addToBackStack(fragmentTag)
                    .commit();

        } else {
            getSupportFragmentManager()
                    .beginTransaction()
                    .replace(R.id.fl_main_container, fragmentToLoad, fragmentTag)
                    .setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                    .commit();
        }
    }



}
0 голосов
/ 26 апреля 2018

Вы можете просто установить свойство RetainInstance внутри OnCreate класса фрагмента.

public override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);
    RetainInstance = true;
}

Сохранить объект Fragment при вращении

0 голосов
/ 14 апреля 2013

Я определил Fragment в макете активности, onSaveInstanceState в Fragment действительно вызывается, но savedInstanceState Bundle в onCreatView фрагмента приходит как ноль.

Причина была в том, что у моего Fragment не было идентификатора в XML:

android:id="@+id/compass_fragment" ...
...