Search code examples
android-studioboolean-logicandroid-savedstate

Persistent booleans Android Studio


I've been poking around the web (including SO), and have found lots of information on having persistent data. I've found strings, ints, doubles, calendars, just about everything. The ones I haven't seen a specific guide or tutorial for are booleans.

I've created an app which has a switch located on the main activity. I do not have a settings button, window, or even a pane, because the entire app is accessed from the main activity. I want to have the switch be persistent as well as the affects it holds (ie, when the app is closed, it will remember if the user disable or enable the vibrate function).

I have the switch to work where it does enable the vibration depending on which position the switch is in. I can't seem to get the switch to remain in the off position when the app is recreated.

Here's my code to save:

@Override
protected void onCreate(Bundle bundle) {
    super.onCreate(bundle);
    setContentView(R.layout.activity_main);
    dBell = MediaPlayer.create(this, R.raw.doorbell);
    if ((bundle != null) && (bundle.getBoolean("vibetoggle") != false)) {
        vibeOn = false;
    } else {
        vibeOn = true;
    }

}

protected void onRestoreInstanceState(Bundle bundle) {
    super.onRestoreInstanceState(bundle);
    vibeOn = bundle.getBoolean("vibetoggle");
}

protected void onSaveInstanceState(Bundle bundle) {
    super.onSaveInstanceState(bundle);
    bundle.putBoolean("vibetoggle", vibeOn);
}

public void onToggleClicked(View view) {
    Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
    vibeOn = ((Switch) view).isChecked();
    if (vibeOn) {
        vibe.vibrate(100);
    } else {
        // No vibrate
    }
}

public void playSound(View view) {
    dBell.start();
    if (vibeOn) {
        Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
        vibe.vibrate(300);
    } else {
        // No vibrate
    }
}

The shorter duration vibrate (100ms) is occurs when the switch is flipped from disabled to enabled. The longer one is what actually causes the button to vibrate when clicked.

I've kind of gotten the boolean logic to work, but the IO switch would still be set to default and wouldn't function correctly until it had been switched. The issue I have regarding the switch, is that I want the switch to be in the correct position when loaded (ie, if the boolean is saved false, then the switch will load in the off position). I can't figure out how to make the two communicate. I would assume the switch would have to change based on the boolean, rather than the other way around. I just can't figure out how to make the xml switch communicate with the one I have in java and visa versa.

Here's the xml code for the switch:

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Vibration"
    android:id="@+id/switch1"
    android:layout_alignBottom="@+id/dBellButton"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:clickable="true"
    android:checked="true"
    android:onClick="onToggleClicked" />

I know the android:checked="true" causes the switch to be created in a default on position. I tried making a new boolean inside of the values xml (so rather than the code saying android:checked="true", it would say something along the lines of android:checked="@bool/vibeConvert), but found I didn't know how to edit the boolean through the java when it was there as well.

I've tried a few different methods to get this data to be persistent, but none of them worked for me. If I could get some help with persistent data, specifically regarding booleans, that would be fantastic.

EDIT: showing my attempt to use SharedPreferences.

protected void onRestoreInstanceState(Bundle bundle) {
    super.onRestoreInstanceState(bundle);
    vibeOn = bundle.getBoolean("vibetoggle");
//        preferenceSettings = getPreferences(PREFERENCE_MODE_PRIVATE);
//        vibeOn = preferenceSettings.getBoolean("on", true);
}

protected void onSaveInstanceState(Bundle bundle) {
    super.onSaveInstanceState(bundle);
    bundle.putBoolean("vibetoggle", vibeOn);
//        preferenceSettings = getPreferences(PREFERENCE_MODE_PRIVATE);
//        preferenceEditor = preferenceSettings.edit();
//        preferenceEditor.putBoolean("on", vibeOn);
//        preferenceEditor.apply();
}

I'm not quite sure how how to use the SharedPreferences, and I couldn't find anywhere which specified where to place them. They are commented out here for obvious reasons. Not sure where to go from here.

Thanks!

Nathan

EDIT:

I tried using the following code:

public static final String PREFS_NAME = "MyPrefsFile";
MediaPlayer dBell;
boolean vibeOn;

@Override
protected void onCreate(Bundle bundle) {
    super.onCreate(bundle);
    setContentView(R.layout.activity_main);
    dBell = MediaPlayer.create(this, R.raw.doorbell);

    // Restore preferences
    SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
    boolean vibeSave = settings.getBoolean("vibeSave", vibeOn);
    vibeOn = vibeSave;
    Switch ("+id/switch1") = vibeSave;
}

@Override
protected void onStop() {
    super.onStop();

    // Let Editor make preference changes
    // All objects are from android.context.Context
    SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
    SharedPreferences.Editor editor = settings.edit();
    editor.putBoolean("vibeSave", vibeOn);
    editor.commit();
}

Here's my XML:

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Vibration"
    android:id="@+id/switch1"
    android:layout_alignBottom="@+id/dBellButton"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:clickable="true"
    android:checked="true"
    android:onClick="onToggleClicked" />

I'm not sure if:

  1. The boolean value is being saved.

  2. The switch can be edited inside of the java code.

I've tried to play with the idea with the following line of code: Switch ("+id/switch1") = vibeSave;, but that didn't work. I'm not sure how to proceed from here. I want my XML to be able to start in the correct position based on the value in the boolean, but I'm not sure how to make my XML and my java talk to each other.


Solution

  • You can use SharedPreferences to store primitive values.

    The best place to do this, is right after the value is changed.

    So add the saving to the logic of your switch listener, and the loading to the logic of your switch initializer.

    To get a SharedPreferences object for your application, use one of two methods:

    getSharedPreferences() - Use this if you need multiple preferences files identified by name, which you specify with the first parameter.

    getPreferences() - Use this if you need only one preferences file for your Activity. Because this will be the only preferences file for your Activity, you don't supply a name.

    To write values:

    Call edit() to get a SharedPreferences.Editor.

    Add values with methods such as putBoolean() and putString().

    Commit the new values with commit()

    To read values, use SharedPreferences methods such as getBoolean() and getString().

    The code in your onCreate should look something like this:

    @Override
    protected void onCreate(Bundle bundle) {
        (...)
        SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        boolean vibeSave = settings.getBoolean("vibeSave", false);
        Switch switch = (Switch) findViewById(R.id.switch1);
        switch.setChecked(vibeSave);
    }