Search code examples
androidonsaveinstancestate

My app keeps crashing after overriding onSaveInstanceState


I have a piece of code that is meant to help me understand how to override the onSaveInstanceState method in order to preserve some data in case the device is rotated.

The code is very simple and does nothing interesting: there's two buttons, when the user clicks any of them, it disables both of them. It works just fine, except that, after the buttons are disabled, if you rotate the device, they come back enabled.

I have added an overriding to onSaveInstanceState, but now it crashes with rotation. I don't know what I'm doing wrong.

Here's the code:

There's two buttons:

private Button mButton1;
private Button mButton2;

A method that takes a Button and a boolean as parameters, so I can toggle the buttons:

public void disBut(Button x, boolean enbl){

        x.setEnabled(enbl);
    }

A method that uses the previous method to disable both buttons, to be called with the Listeners:

private void checkAnaswer(boolean userTrue){   

        disBut(mButton1, false);
        disBut(mButton2, false);
    }

And the Listeners on the Buttons:

   mButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkAnaswer(true);    
            }
        });    
        mButton2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkAnaswer(false);   
            }
        });

All of this works fine. Now for the overriding of onSavedInstance:

I have two keys, and two booleans. One for each Button:

     boolean bundleBt1;
boolean bundleBt2;

private static final String BUTTON_ONE = "one";
private static final String BUTTON_TWO = "two";

Then, I check to see if any of the Buttons are enabled, assign a value to the booleans accordingly, and save them along with the key, as a key-value pair:

 @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);

         bundleBt1 = mButton1.isEnabled() ? true : false;
         bundleBt2 = mButton2.isEnabled() ? true : false;

        savedInstanceState.putBoolean(BUTTON_ONE, bundleBt1);
        savedInstanceState.putBoolean(BUTTON_TWO, bundleBt2);   
    }

Lastly, after calling the superclass, I check to see if it's not empty. If it is not, I assign to each boolean the value stored in it's respective key, and use the booleans inside the method that enables/disables the Buttons.

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        if (savedInstanceState != null) {

            bundleBt1 = savedInstanceState.getBoolean(BUTTON_ONE);
            disBut(mButton1, bundleBt1);

            bundleBt2 = savedInstanceState.getBoolean(BUTTON_TWO);    
            disBut(mButton2, bundleBt2);    
        }

Just to be certain that there's nothing wrong with the syntax of the code, here it is in it's integrity:

public class MainActivity extends AppCompatActivity {

    private Button mButton1;
    private Button mButton2;

    boolean bundleBt1;
    boolean bundleBt2;

    private static final String BUTTON_ONE = "one";
    private static final String BUTTON_TWO = "two";      

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        if (savedInstanceState != null) {

            bundleBt1 = savedInstanceState.getBoolean(BUTTON_ONE);
            disBut(mButton1, bundleBt1);

            bundleBt2 = savedInstanceState.getBoolean(BUTTON_TWO);    
            disBut(mButton2, bundleBt2);    
        }   

        mButton1 = (Button) findViewById(R.id.true_button);
        mButton2 = (Button) findViewById(R.id.false_button);    

        mButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkAnaswer(true);    
            }
        });


        mButton2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkAnaswer(false);   
            }
        });    
    }   

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);

         bundleBt1 = mButton1.isEnabled() ? true : false;
         bundleBt2 = mButton2.isEnabled() ? true : false;

        savedInstanceState.putBoolean(BUTTON_ONE, bundleBt1);
        savedInstanceState.putBoolean(BUTTON_TWO, bundleBt2);   
    }
 private void checkAnaswer(boolean userTrue){  

        disBut(mButton1, false);
        disBut(mButton2, false);
    }

    public void disBut(Button x, boolean enbl){

        x.setEnabled(enbl);
    }    
}

Solution

  •     setContentView(R.layout.activity_main);
        if (savedInstanceState != null) {
    
            bundleBt1 = savedInstanceState.getBoolean(BUTTON_ONE);
            disBut(mButton1, bundleBt1);
    
            bundleBt2 = savedInstanceState.getBoolean(BUTTON_TWO);    
            disBut(mButton2, bundleBt2);    
        }   
    
        mButton1 = (Button) findViewById(R.id.true_button);
        mButton2 = (Button) findViewById(R.id.false_button);
    

    If savedInstanceStateis not null the disButfunction will run on null object since your are inflating your buttons later. I have not seen your stack trace but thats an error for sure.

    Inflate your buttons (mButton1 = (Button) findViewById(R.id.true_button); mButton2 = (Button) findViewById(R.id.false_button);) previous to restore the activity state.