Search code examples
javaandroidscrollviewspinner

java.lang.IllegalStateException in ScrollView when rotating device


I'm using a ScrollView, called fragmentView below, to host a custom Fragment inside of it, and it generally works fine. However, when I rotate my device into landscape mode and back, the app crashes saying

java.lang.IllegalStateException: ScrollView can host only one direct child

I add the Fragment when a Spinner item is clicked like this:

fragmentView.removeAllViews();

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
ConfigureFragment fragment = new ConfigureFragment();
fragment.setReferences(MainActivity.this, (Controller) spinner.getSelectedItem());
fragmentTransaction.add(fragmentView.getId(), fragment, "");
fragmentTransaction.commit();

I used removeAllViews to make sure that the ScrollView is empty before I add anything new. This is the layout file for my fragment:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ConfigureFragment">

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:stretchColumns="0">

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <EditText
                android:id="@+id/editTextName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:ems="10"
                android:gravity="center"
                android:inputType="textPersonName"
                android:padding="10dp" />
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:gravity="center"
                android:text="@string/esp_channel" />
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <SeekBar
                android:id="@+id/seekBarRed"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:max="@integer/esp_value_max"
                android:progress="@integer/esp_value_min" />

            <EditText
                android:id="@+id/editTextRed"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:ems="10"
                android:inputType="number"
                android:padding="10dp" />

        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <SeekBar
                android:id="@+id/seekBarGreen"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:max="@integer/esp_value_max"
                android:progress="@integer/esp_value_min" />

            <EditText
                android:id="@+id/editTextGreen"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:ems="10"
                android:inputType="number"
                android:padding="10dp" />

        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <SeekBar
                android:id="@+id/seekBarBlue"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:max="@integer/esp_value_max"
                android:progress="@integer/esp_value_min" />

            <EditText
                android:id="@+id/editTextBlue"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:ems="10"
                android:inputType="number"
                android:padding="10dp" />

        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <Button
                android:id="@+id/buttonRefresh"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:text="@string/esp_retrieve" />
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="@string/esp_connection" />
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/textView3"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="fill_vertical"
                android:padding="10dp"
                android:text="@string/esp_ip" />

            <EditText
                android:id="@+id/editTextIP"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ems="10"
                android:inputType="date"
                android:padding="10dp" />
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/textView4"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="fill_vertical"
                android:padding="10dp"
                android:text="@string/esp_port" />

            <EditText
                android:id="@+id/editTextPort"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ems="10"
                android:inputType="number"
                android:padding="10dp" />

        </TableRow>

    </TableLayout>

</android.support.constraint.ConstraintLayout>

Solution

  • Solution 1

    Use replace() instead of add() for adding the fragment to container

    When Activity is restarted due to orientation change, Activity is created once yet ConfigureFragment is created twice.

    The reason is because system restores the activity and fragment automatically if app got killed by system. The scene happens in super.onCreate(). Therefore, the add fragment code above will add an extra fragment on top of the restored fragment which lead to the current situation. ScrollView cannot have more than one child!

    Solution 2

    If you are adding the fragment in onCreate() method of your activity, then check for savedInstanceState variable (Bundle object). It's not null when activity is recreated, then only add your fragment

    if (savedInstanceState == null) {
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        ConfigureFragment fragment = new ConfigureFragment();
        fragment.setReferences(MainActivity.this, (Controller) spinner.getSelectedItem());
        fragmentTransaction.add(fragmentView.getId(), fragment, "");
        fragmentTransaction.commit();
    }