Состояние восстановления фрагментов при изменении ориентации

Мне нужно реализовать в своем приложении "стандартную" навигацию по фрагментам (см. ссылку ).

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

Я пытался сделать это двумя разными способами:

1) Я использую только одно занятие с разным макетом книжной и альбомной ориентации.

Вертикальный макет xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/main_frame_fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

А вот ландшафтный макет:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false"
    android:orientation="horizontal" >

    <FrameLayout
        android:id="@+id/main_frame_fragment_container_left"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <FrameLayout
        android:id="@+id/main_frame_fragment_container_right"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

Метод действия onCreate:

    private static ItemsFragment mItemsFragment;
    private static ItemDetailsFragment mItemDetailsFragment;

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

        if (mItemsFragment == null) {
            mItemsFragment = ItemsFragment.newInstance();
        }
        if (mItemDetailsFragment == null) {
            mItemDetailsFragment = ItemDetailsFragment.newInstance();
        }

        if (isLandscape()) {
            getSupportFragmentManager().beginTransaction().replace(R.id.main_frame_fragment_container_left, mItemsFragment)
                    .commit();
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.main_frame_fragment_container_right, mItemDetailsFragment).commit();
        } else {
            getSupportFragmentManager().beginTransaction().replace(R.id.main_frame_fragment_container, mItemsFragment)
                    .commit();
        }
    }

И вот так я обновляю 2-й фрагмент:

Bundle bundle = new Bundle();
bundle.putSerializable(BaseFragment.KEY_BUNDLE_ITEM, response.getItem());
mItemDetailsFragment = ItemDetailsFragment.newInstance(bundle);
if (isLandscape()) {
    getSupportFragmentManager().beginTransaction()
                            .replace(R.id.main_frame_fragment_container_right, mItemDetailsFragment).commit();
} else {
    getSupportFragmentManager().beginTransaction()
                            .replace(R.id.main_frame_fragment_container, mItemDetailsFragment).addToBackStack(null).commit();
}

Также я сохраняю и восстанавливаю состояния фрагментов, поэтому мои данные не пропадают после поворотов. В общем, в моем случае этот код работает правильно.

2) Я использую два занятия и один и тот же макет для первого занятия в портретном и ландшафтном режимах.

xml макет такой же, как и в предыдущем для альбомной ориентации:

    <FrameLayout
        android:id="@+id/main_frame_fragment_container_left"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <FrameLayout
        android:id="@+id/main_frame_fragment_container_right"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

onCreate (обратите внимание, что сущности фрагментов не статичны, как в первом случае): private ItemsFragment mItemsFragment; частный ItemDetailsFragment mItemDetailsFragment;

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

    if (savedInstanceState == null) {
        mItemsFragment = ItemsFragment.newInstance();
        mItemDetailsFragment = ItemDetailsFragment.newInstance();

        getSupportFragmentManager().beginTransaction().replace(R.id.main_frame_fragment_container_left, mItemsFragment)
        .commit();
        getSupportFragmentManager().beginTransaction()
        .replace(R.id.main_frame_fragment_container_right, mItemDetailsFragment).commit();
    }
}

И теперь, если устройство находится в портретном режиме, я запускаю новое Activity:

if (isLandscape()) {
    Bundle bundle = new Bundle();
    bundle.putSerializable(BaseFragment.KEY_BUNDLE_ITEM, response.getItem());
    mItemDetailsFragment = ItemDetailsFragment.newInstance(bundle);
    getSupportFragmentManager().beginTransaction()
        .replace(R.id.main_frame_fragment_container_right, mItemDetailsFragment).commit();
} else {
    Intent intent = new Intent(getApplicationContext(), DetailsActivity.class);
    intent.putExtra(KEY_ITEM, response.getItem());
    startActivity(intent);
}

И, наконец, метод onCreate 2-го Activity:

protected void onCreate(Bundle arg0) {
    super.onCreate(arg0);
    setContentView(R.layout.activity_details);

    if (isLandscape()) {
        finish();
    }

    Item item = (Item) getIntent().getExtras().getSerializable(KEY_ITEM);

    Bundle bundle = new Bundle();
    bundle.putSerializable(BaseFragment.KEY_BUNDLE_ITEM, item);

    ItemDetailsFragment mItemDetailsFragment = ItemDetailsFragment.newInstance(bundle);

    getSupportFragmentManager().beginTransaction()
        .replace(R.id.main_frame_fragment_container, mItemDetailsFragment).commit();
}

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

Вопрос:

В 1-м случае я сохраняю фрагменты как статические переменные, и из-за этого меня не волнует, изменю ли я состояние 2-го фрагмента в портретном или ландшафтном режимах (используется тот же фрагмент). Но я не думаю, что стоит сохранять его как статические поля.

Во втором случае я не знаю, как синхронизировать Activity A Fragment B (пейзаж) и Activity B Fragment B (портрет). Если я что-то изменил во фрагменте (я имею в виду кнопку переключения и т. Д.) И повернул устройство, изменения должны быть применены в другом фрагменте.

Как правило, какой вариант лучше, а второй - как решить проблему с синхронизацией? Или, может быть, есть другой способ попроще. Спасибо за чтение, надеюсь, вы мне поможете :)




Ответы (1)


Просто следуйте за этим товарищем http://developer.android.com/guide/components/fragments.html. Не делайте фрагменты статичными (это просто странно)

person Pulkit Sethi    schedule 08.08.2013
comment
Спасибо, это то, что мне нужно. Что-то меня вчера смутило в этом посте, но даже не помню, что именно. - person UneXp; 09.08.2013
comment
Не только странно, но и утечка памяти. - person mwieczorek; 13.03.2017
comment
странные вещи приводят к странным сбоям - ›утечки памяти: 0 - person Pulkit Sethi; 14.03.2017