Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fragments restore state on orientation changed

I have to implement "standart" fragments navigation in my app (please see link).

The issue is when device is in portrait mode, there should be shown only 1 fragment, and when it is rotated to landscape mode, 2 fragments should be shown.

I tried to do this 2 different ways:

1) I use only 1 activity with different portrait and landscape layouts.

Portrait layout 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>

And here`s landscape layout:

<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>

Activity`s onCreate method:

    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();
        }
    }

And that`s the way I refresh 2nd fragment:

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();
}

Also I save and restore fragments` states, so my data does not disappear after rotations. Generally, this code works properly in my case.

2) I use 2 activities and the same layout for 1st Activity portrait and landscape modes.

xml layout is the same as in previous one for landscape:

    <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 method (note, that fragments entities are not static, as it was in 1st case): private ItemsFragment mItemsFragment; private 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();
    }
}

And now if the device is in portrait mode, I start new 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);
}

And, at last, 2nd Activity`s onCreate method:

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();
}

When device is rotated to landscape mode, 2nd activity finishes, and I see my 1st activity with 2 fragments (as expected).

Question:

In 1st case I save fragments as static variables, and because of this I don't care if I change 2nd fragment state in portrait or landscape modes (the same fragment is used). But I don't think it's a good idea to save it as static fields.

In 2nd case I don't know how to sync Activity A Fragment B (landscape) and Activity B Fragment B (portrait). If I change something in fragment (I mean, toggle button etc) and rotate device, changes should be applied in another fragment.

Generally, what case is better, and if 2nd, how can I resolve synchronization issue? Or maybe there is another easier way. Thanks for reading, I hope you can help me :)

like image 775
UneXp Avatar asked Aug 08 '13 23:08

UneXp


People also ask

How do I stop android from restarting activity when changing orientations?

If you want the activity to not restart during screen orientation change, you can use the below AndroidManifest. xml. Please note the activity android:configChanges=”orientation|screenSize” attribute. This attribute makes the activity not restart when change screen orientation.

What happens when screen orientation changes in android?

When you rotate your device and the screen changes orientation, Android usually destroys your application's existing Activities and Fragments and recreates them. Android does this so that your application can reload resources based on the new configuration.

How do you retain a fragment state?

The first key is that we can save our Fragments' state ourselves using FragmentManager. saveInstanceState(Fragment) . Before removing the Fragment, call this method to get a Bundle containing your Fragment's saved state! The second key is restoring state.


1 Answers

Just follow this mate http://developer.android.com/guide/components/fragments.html. Dont make fragments static (thats just wierd)

like image 175
Pulkit Sethi Avatar answered Oct 16 '22 15:10

Pulkit Sethi