Search code examples
androidandroid-fragmentsorientation-changesandroid-togglebuttonandroid-switch

Ho do I properly handle TextView bound to Switch on orientation change, in fragment


As the title suggests, how do I avoid the TextView to lose its text after an orientation change?
Notice how the TextView is bound to the Switch: the initial text (defined in XML) is OFF (because the Switch is initially in the off state) and, on every Switch state change, the TextView's text is changed accordingly.

Expected behavior:

  1. Open app: Switch is off, TextView is OFF
  2. Turn on the Switch: TextView is ON
  3. Rotate the device: Switch stays on and TextView stays ON as well

Actual behavior:

  1. Open app: Switch is off, TextView is OFF
  2. Turn on the Switch: TextView is ON
  3. Rotate the device: Switch stays on, but TextView is OFF

The following happens because the Fragment is redrawn and since the OnCheckedChangeListener is called on every orientation change (My question: SwitchCompat OnCheckedChangeListener called on every orientation change of Fragment), but the handling only happens if the Switch was actually pressed (to avoid the problem in the question above), the TextView is drawn with the default text in XML.

Behavior without isPressed():

  1. Open app: Switch is off, TextView is OFF
  2. Turn on the Switch: TextView is ON
  3. Rotate the device: Switch "stays" on and TextView "stays" ON as well BUT the OnCheckedChangeListener is called again, and I want to avoid this because I want a call there ONLY if the user actually toggled the Switch

MainFragment.java:

public class MainFragment extends Fragment implements CompoundButton.OnCheckedChangeListener {

    private AppCompatTextView appCompatTextView;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        final View rootView = inflater.inflate(R.layout.main_fragment, container, false);
        appCompatTextView = rootView.findViewById(R.id.app_compat_textview);
        final SwitchMaterial switchMaterial = rootView.findViewById(R.id.switch_material);
        switchMaterial.setOnCheckedChangeListener(this);
        return rootView;
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (buttonView.isPressed()) {
            if (isChecked) {
                appCompatTextView.setText("ON");
            } else {
                appCompatTextView.setText("OFF");
            }
        }
    }
}

Solution

  • The fragment is getting destroyed on every orientation change. Hence all UI elements are redrawn. What you need is to save and restore fragment instance on orientation change. Refer to this answer for how to.