Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatic UI configuration change handling in Activity and Fragment sometimes fails

I have written android app now for a long time but now I'm facing a problem that I have never thought about. It is about the android lifecycle of Activitys and Fragments in in relation to configuration changes. For this I have create a small application with this necessary code:

public class MainActivity extends FragmentActivity {

    private final String TAG = "TestFragment";
    private TestFragment fragment;

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

        FragmentManager fm = getSupportFragmentManager();
        fragment = (TestFragment) fm.findFragmentByTag(TAG);

        if (fragment == null) {
            fragment = new TestFragment();
            fm.beginTransaction().add(R.id.fragment_container, fragment, TAG).commit();
        }
    }
}

And here is my code for the TestFragment. Note that I'm calling setRetainInstance(true); in the onCreate method so the fragment is not recrated after a configuration change.

public class TestFragment extends Fragment implements View.OnClickListener {

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

    @Override
    public View onCreateView(LayoutInflater li, ViewGroup parent, Bundle bundle) {
        View rootView = li.inflate(R.layout.fragment_test, parent, false);
        Button button = (Button) rootView.findViewById(R.id.toggleButton);

        button.setOnClickListener(this);
        return rootView;
    }

    @Override
    public void onClick(View v) {
        Button button = (Button) v;
        String enable = getString(R.string.enable);

        if(button.getText().toString().equals(enable)) {
            button.setText(getString(R.string.disable));
        } else {
            button.setText(enable);
        }
    }
}

And here is the layout that my fragment is using:

<LinearLayout
    ...>

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/toggleButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/enable"/>

</LinearLayout>

My problem is that if I rotate the device the text of the Button change back to the default value. Of course the View of the Fragment is new created and inflated but the saved instance for the Views should be restored. I also have an EditText in my layout and there the text and other properties remains after the rotation. So why is the Button not restore from the Bundle by default? I have read on the developer site:

By default, the system uses the Bundle instance state to save information about each View object in your activity layout (such as the text value entered into an EditText object). So, if your activity instance is destroyed and recreated, the state of the layout is restored to its previous state with no code required by you.

I've also read a lot of answers the last days but I do not know how actual they are anymore. Please do not leave a comment or an answer with android:configChanges=... this is very bad practice. I hope someone can bring light into my lack of understanding.

like image 871
Cilenco Avatar asked Aug 13 '15 17:08

Cilenco


People also ask

What cases that create a configuration change in Android?

In Android applications, each time a user rotates the screen, keyboard availability, etc., it is known as a configuration change. Configuration changes occur at runtime based on user actions. When such changes occur, Android components like Activities get recreated or restart.

What is setRetainInstance true?

setRetainInstance(true); // Start up the worker thread. mThread.start(); } /** * This is called when the Fragment's Activity is ready to go, after * its content view has been installed; it is called both after * the initial fragment creation and after the fragment is re-attached * to a new activity.

What is the purpose of activity and fragments in Android development What is the difference between an activity and a fragment are they dependent on each other?

Activity is an application component that gives a user interface where the user can interact. The fragment is only part of an activity, it basically contributes its UI to that activity. Fragment is dependent on activity. It can't exist independently.


2 Answers

You should save state of your fragment in the onSaveInstanceState(Bundle outState) and restore it in the onViewCreated(View view, Bundle savedState) method. This way you will end up with the UI just as it was before configuration change.

like image 160
MatBos Avatar answered Oct 16 '22 05:10

MatBos


TextView subclasses don't save their text by default. You need to enable freezesText="true" in the layout, or setFreezesText(true) at runtime for it to save its state.

like image 37
Kevin Coppock Avatar answered Oct 16 '22 05:10

Kevin Coppock