Android Input and Shared Preferences

Introduction

Every app involves data. Most data are supplied by users through the various input controls, such as text field, check box, radio group, spinner, and button. While some data is transient, most will require to stay or persist even after the app has stopped running. Android provides many ingenious technologies for storing persistent data locally.

In this book, you will start by learning how to implement and handle input controls of text field, check box, radio group, spinner, and button. You will then learn to store and retrieve data using Shared Preferences.

Setting the Stage

On your favorite Android IDE, start a new Android app project. Let’s give it an application name of “AndroidInputNStorage” and a domain name of “peterleowblog.com“. The resulting package name of your project will be “com.peterleowblog.androidinputnstorage“.

In the “res” folder of the project, replace the content of the “strings.xml” with the following string resources that will be used in the project.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Android Input and Storage</string>
    <string name="action_settings">Settings</string>
    <string name="shared_preferences">Shared Preferences</string>
    <string name="email">Email</string>
    <string name="gender">Gender</string>
    <string name="female">Female</string>
    <string name="male">Male</string>
    <string name="hobbies">Hobbies</string>
    <string name="coding">Coding</string>
    <string name="writing">Writing</string>
    <string name="jogging">Jogging</string>
    <string name="zodiac">Zodiac</string>
    <string name="save_me">Save Me</string>
    <string name="retrieve">Get Me</string>

    <string-array name="zodiac">
        <item>Aries</item>
        <item>Taurus</item>
        <item>Gemini</item>
        <item>Cancer</item>
        <item>Leo</item>
        <item>Virgo</item>
        <item>Libra</item>
        <item>Scorpio</item>
        <item>Sagittarius</item>
        <item>Capricorn</item>
        <item>Aquarius</item>
        <item>Pisces</item>
    </string-array>

</resources>

Handling Input

Create a new activity called “SharedPreferencesActivity” with its layout file “activity_shared_preferences.xml”. Replace the content in the activity_shared_preferences.xml” with the following XML code:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:paddingTop="16dp"
        android:paddingBottom="16dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="@string/shared_preferences"
            android:id="@+id/textView"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="textEmailAddress"
            android:ems="10"
            android:id="@+id/txtEmail"
            android:layout_below="@+id/textView4"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="@string/email"
            android:id="@+id/textView4"
            android:layout_below="@+id/textView"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="@string/gender"
            android:id="@+id/textView5"
            android:layout_below="@+id/txtEmail"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true" />

        <RadioGroup
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/textView5"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:id="@+id/radioGroupGender">

            <RadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/male"
                android:id="@+id/radMale"
                android:checked="false" />

            <RadioButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/female"
                android:id="@+id/radFemale"
                android:checked="false" />

        </RadioGroup>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="@string/hobbies"
            android:id="@+id/textView6"
            android:layout_below="@+id/radioGroupGender"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true" />

        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/coding"
            android:id="@+id/chkCoding"
            android:onClick="onCheckboxClicked"
            android:checked="false"
            android:layout_below="@+id/textView6"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true" />

        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/writing"
            android:id="@+id/chkWriting"
            android:onClick="onCheckboxClicked"
            android:layout_below="@+id/chkCoding"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:checked="false" />

        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/jogging"
            android:id="@+id/chkJogging"
            android:onClick="onCheckboxClicked"
            android:layout_below="@+id/chkWriting"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:checked="false" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="@string/zodiac"
            android:id="@+id/textView7"
            android:layout_below="@+id/chkJogging"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true" />

        <Spinner
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/spinnerZodiac"
            android:layout_below="@+id/textView7"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/save_me"
            android:id="@+id/btnSave"
            android:onClick="save"
            android:layout_below="@+id/spinnerZodiac"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/retrieve"
            android:onClick="retrieve"
            android:id="@+id/btnRetrieve"
            android:layout_alignParentBottom="true"
            android:layout_alignRight="@+id/spinnerZodiac"
            android:layout_alignEnd="@+id/spinnerZodiac" />

    </RelativeLayout>

</ScrollView>

The “activity_shared_preferences.xml” will render a UI page as shown in Figure 1:

Figure 1: SharedPreferencesActivity Page

Figure 1: SharedPreferencesActivity Page

The user interface (UI) comprises the following controls:

  • One “EditText” text field for email input.
  • One “RadioGroup” control with two “RadioButtons” for gender selection.
  • Three “CheckBox” controls for hobbies selection.
  • One “Spinner” control for zodiac selection.
  • Two “Button” controls – one each for saving and retrieving data respectively.

The subsequent sections of this chapter will guide you to complete the code for the “SharedPreferencesActivity.java”:

Initialization

In the “SharedPreferencesActivity.java”, add the following code to import the necessary Android packages, and declare and initialize class variables:

package com.peterleowblog.androidinputnstorage;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.Toast;

public class SharedPreferencesActivity extends Activity {

    private String email;
    private String gender;
    private String hobbies;
    private String zodiac;
    public static final String STORAGE_NAME = "";

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

        email = "";
        gender = "";
        hobbies = "";
        zodiac = "";

        // Add other code
    }
        // Add other methods
}

 Handling “EditText” Field

In order to capture input value in the “Email” “EditText” field, you will must first find out the value of the “android:id” attribute from its “<EditText>” node in the “activity_shared_preferences.xml” , which is:

android:id="@+id/txtEmail"

This “Email” “EditText” field can then be reference in Java code as:

R.id.txtEmail

Similarly, you can access all Android UI controls in Java code using the approach above.

The Java code to get the value from this “Email” “EditText” field is:

((EditText)findViewById(R.id.txtEmail)).getText().toString();

The Java code to set a value to this “Email” “EditText” field is:

((EditText)findViewById(R.id.txtEmail)).setText(“blahblah@gmail.com”);

You will add the code to get and set the value of “Email” “EditText” field to “SharedPreferencesActivity.java” later on.

Handling RadioGroup

In order to capture the item selected in the Gender “RadioGroup” for further processing, set the “SharedPreferencesActivity” class as an OnCheckedChangeListener to it. The process is as follows:

First, implement the “OnCheckedChangeListener” interface on the “SharedPreferencesActivity” class.

public class SharedPreferencesActivity extends Activity implements RadioGroup.OnCheckedChangeListener {
    // ... other code ...
}

Next, add the method for the “OnCheckedChangeListener” interface to the “SharedPreferencesActivity” class.

// Add other methods
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
    int radioButtonId = radioGroup.getCheckedRadioButtonId();
    RadioButton radioButton = (RadioButton)radioGroup.findViewById(radioButtonId);
    gender = radioButton.getText().toString();
}

Lastly, inside the “onCreated()” method, add the code to set the “SharedPreferencesActivity” class as an OnCheckedChangeListener to the “RadioGroup” object.

RadioGroup radioGroupGender = (RadioGroup) findViewById(R.id.radioGroupGender);
radioGroupGender.setOnCheckedChangeListener(this);

You have completed the code for the “RadioGroup” control. Whenever the user makes a selection on the Gender “RadioGroup”, it will trigger the “onCheckedChanged()” event handler method which contains code to assign the selected gender item to the “gender” variable.

Handling CheckBox

To capture the item selected in the Hobbies “CheckBox” controls for further processing, the app have to implement an “onClick()” event handler on all the “CheckBox” controls.  The process is as follows:

First, notice that an ‘android:onClick=”onCheckboxClicked”‘ attribute has been added to all the “<checkbox>” nodes in the “activity_shared_preferences.xml” to bind them to a method called “onCheckboxClicked()” that will handle the click event.

android:onClick="onCheckboxClicked"

Next, add the “onCheckboxClicked()” method to the “SharedPreferencesActivity” class to handle the “onClick()” event on all the “CheckBox” controls.

public void onCheckboxClicked(View view) {

    CheckBox chkJogging = (CheckBox) findViewById(R.id.chkJogging);
    CheckBox chkCoding = (CheckBox) findViewById(R.id.chkCoding);
    CheckBox chkWriting = (CheckBox) findViewById(R.id.chkWriting);

    StringBuilder sb = new StringBuilder();

    if (chkJogging.isChecked()) {
        sb.append(", " + chkJogging.getText());
    }

    if (chkCoding.isChecked()) {
        sb.append(", " + chkCoding.getText());
    }

    if (chkWriting.isChecked()) {
        sb.append(", " + chkWriting.getText());
    }

    if (sb.length() > 0) { // No toast if the string is empty
        // Remove the first comma
        hobbies = sb.deleteCharAt(sb.indexOf(",")).toString();
    } else {
        hobbies = "";
    }
}

You have completed the code for the “CheckBox” controls. Whenever the user checks or unchecked any of the hobbies “CheckBox” controls, it will trigger the  “onCheckboxClicked()” method that contains the code to concatenate selected hobbies and assign them to the “hobbies” variable.

Handling Spinner

To populate the “Spinner” with the zodiac data, create an ArrayAdapter“, a subclass of “Adapter” class, to bridge the data source, i.e. the string array resource called “zodiac” in the “strings.xml” referenced to in code as “R.array.zodiac”, and the “View”, i.e. the “Spinner”. “ArrayAdapter” is also responsible for making a “TextView” to contain each item in the data source.  To achieve this, add the following code to the “onCreated()” method:

Spinner spinnerZodiac = (Spinner) findViewById(R.id.spinnerZodiac);
// Populate the spinner with data source
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.zodiac, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerZodiac.setAdapter(adapter);

In order to capture the item selected in the Zodiac “Spinner” for further processing, set the “SharedPreferencesActivity” class as an OnItemSelectedListener to it. The process is as follows:

First, implement the “OnItemSelectedListener” interface on the “SharedPreferencesActivity” class.

public class SharedPreferencesActivity extends Activity implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
    // ... other code ...
}

Next, add the methods for the “OnItemSelectedListener” interface to the “SharedPreferencesActivity” class.

public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    zodiac = parent.getItemAtPosition(position).toString();
}

public void onNothingSelected(AdapterView<?> parent) {
    // An interface callback
}

Lastly, go back to the “onCreated()” method, add the code to set the “SharedPreferencesActivity” class as an OnItemSelectedListener to the “Spinner” object.

// Set a listener on spinner
spinnerZodiac.setOnItemSelectedListener(this);

You have completed the code for the “Spinner” control. Whenever the user makes a selection on the Zodiac “Spinner”, it will trigger the “onItemSelected()” event handler method which contains code to assign the selected zodiac item to the “zodiac” variable.

Handling “Save Me” Button

When the user clicks on the “Save Me” button, the app will save the user’s input data to some storage.  In order to do this, the app have to implement an “onClick()” event handler on the “Save Me” button.  The process is as follows:

First, notice that an ‘android:onClick=”save”‘ attribute has been added to the “Save Me” “<Button>” nodes in the “activity_shared_preferences.xml” to bind the “Save Me” button to a method called “save()” that will handle its click event.

android:onClick="save"

Next, add the “save()” method to the “SharedPreferencesActivity” class to handle the “onClick()” event on the “Save Me” button. Note that the code for getting value from the “Email” “EditText” field is included.

public void save(View view) {
    // Capture email input
    email = ((EditText)findViewById(R.id.txtEmail)).getText().toString();

    // To add code to save data to storage later on
}

You have completed the code for the “Save Me” button. Whenever the user click on this button,  it will trigger the “save()” method that contains code to capture the Email input in the “EditText” text field using the getText() method and assign it to the “email” variable before saving to some storage. The actual code for saving to storage will differ depending on the storage types.

Handling “Get Me” Button

When the user clicks on the “Get Me” button, the app will retrieve stored data and populate the UI controls with the data. Similar to the “Save Me” button, in order to do this, the app have to implement an “onClick()” event handler on the “Get Me” button.  The process is as follows:

First, notice that an ‘android:onClick=”retrieve”‘ attribute has been added to the “Get Me” “<Button>” nodes in the “activity_shared.xml” to bind the “Get Me” button to a method called “retrieve()” that will handle its click event.

android:onClick="retrieve"

Next, add the “retrieve()” method to the “SharedPreferencesActivity” class to handle the “onClick()” event on the “Get Me” button.

public void retrieve(View view) {
    // To add code to retrieve data from storage later on
    setupUI(); // A method to set the data on the UI controls
}

You have completed the code for the “Get Me” button. Whenever the user click on this button,  it will trigger the “retrieve()” method that contains code to retrieve stored data from some storage, assign the data to the respective class variables, i.e. “email”, “gender”, “hobbies”, and “zodiac”, and call a method “setupUI()” to display the data on the respective UI controls.

Writing “setupUI()” Method

First, insert the “setupUI()” method into the “SharedPreferencesActivity” class:

protected void setupUI(){
    // Add code here
}

Start to add the code bit by bit to the “setupUI()” method. First is the code to set the retrieved email value assigned to the “email” variable to the “Email” “EditText” field using setText() method.

((EditText)findViewById(R.id.txtEmail)).setText(email);

Continue to add this code to select the “Gender” “RadioButton” control that corresponds to the retrieved gender value assigned to the “gender” variable.

RadioButton radMale = (RadioButton)findViewById(R.id.radMale);
RadioButton radFemale = (RadioButton)findViewById(R.id.radFemale);

if (gender.equals("Male")){
    radMale.setChecked(true);
} else if (gender.equals("Female")){
    radFemale.setChecked(true);
} else {
    radMale.setChecked(false);
    radFemale.setChecked(false);
}

Continue to add this code to check the “Hobbies” “CheckBox” controls that corresponds to the retrieved hobbies contained in the “hobbies” variable.

CheckBox chkCoding = (CheckBox)findViewById(R.id.chkCoding);
CheckBox chkWriting = (CheckBox)findViewById(R.id.chkWriting);
CheckBox chkJogging = (CheckBox)findViewById(R.id.chkJogging);

chkCoding.setChecked(false);
chkWriting.setChecked(false);
chkJogging.setChecked(false);

if (hobbies.contains("Coding")) {
    chkCoding.setChecked(true);
}

if (hobbies.contains("Writing")) {
    chkWriting.setChecked(true);
}

if (hobbies.contains("Jogging")) {
    chkJogging.setChecked(true);
}

Finally, set the selected item of the “Zodiac” “Spinner” to the retrieved zodiac value assigned to the “zodiac” variable.

Resources resource = getResources();
String[] zodiacArray = resource.getStringArray(R.array.zodiac);
for(int i = 0; i < zodiacArray.length; i++){
    if(zodiacArray[i].equals(zodiac)){
        ((Spinner)findViewById(R.id.spinnerZodiac)).setSelection(i);
    }
}

Congratulation! You have created an activity called “SharedPreferencesActivity” and learned the different ways of handling input types. You are now ready to implement the shared preferences storage.

Shared Preferences

Android provides the SharedPreferences class that allows an app to persist primitive type of data, such as string, int, long, float, and boolean, in the form of key-value pairs. For example,

KEY VALUE
“email” “xyz@gmail.com”
“gender” “Male”

Learning the Basics

To start using “SharedPreferences”, an app must first obtain an instance of it by calling either one of these two methods—”getPreferences() or “getSharedPreferences() .

  • “getPreferences()” method returns one “SharedPreferences” file that is private to the current activity. For example,
    SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
  • “getSharedPreferences()” method returns one of the multiple “SharedPreferences” files identified by a name which is passed as the first parameter. If the named preferences file does not exist, it will be created when you write and commit changes to it. For example,
    String STORAGE_NAME = "mySharedPreferences";
    SharedPreferences sharedPreferences = getSharedPreferences(STORAGE_NAME, Context.MODE_PRIVATE);

The”MODE_PRIVATE parameter, which is the default, restricts the access to the “SharedPreferences” file to the calling app or apps that share the same user ID.

To write values to a “SharedPreferences” file, follow these steps:

  1. Call the edit() method of the “SharedPreferences” instance to get a SharedPreferences.Editor object. For example,
    SharedPreferences.Editor editor = sharedPreferences.edit();
  2. Add values to the “SharedPreferences” using the appropriate put<DataType> methods of the “SharedPreferences.Editor” object, such as  “putBoolean()”, “putFloat()”, “putInt()”,putLong()“, “putString()”, and “putStringSet()”. These methods take two parametersthe first parameter is the key while the second parameter the value of the preference. For example,
    editor.putString("email", email);
  3. Call either commit() or apply() method of the “SharedPreferences.Editor” object to copy the changes made in the “SharedPreferences.Editor” to the “SharedPreferences“. For example,
    editor.apply();

To read values from a “SharedPreferences”, simply call the appropriate get<DataType> methods of the “SharedPreferences” instance, such as  “getBoolean()”, “getFloat()”, “getInt()”, “getLong()”, “getString()”, and “getStringSet()”. These methods take two parametersthe first parameter is the key of the preference, and the second parameter the default value to return if the preference does not exist. For example,

email = sharedPreferences.getString("email", "");

Having learned the basic of “SharedPreferences”, you will now add a “SharedPreferences” storage type to the project.

Making It Happen

To implement shared preferences  storage on “SharedPreferencesActivity”, follow these steps:

  • Assign “MySharedPreferences” to the “STORAGE_NAME” variable which will be the name of the “SharedPreferences” file.
    public static final String STORAGE_NAME = "MySharedPreferences";
  • Add the code for writing to the “SharedPreferences” file to the “save()” method.
    public void save(View view) {
    
        email = ((EditText)findViewById(R.id.txtEmail)).getText().toString();
    
        SharedPreferences sharedPreferences = getSharedPreferences(STORAGE_NAME, Context.MODE_PRIVATE);
    
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString("email", email);
        editor.putString("gender", gender);
        editor.putString("hobbies", hobbies);
        editor.putString("zodiac", zodiac);
    
        editor.apply();
        
        Toast.makeText(getApplicationContext(), "You have been saved!", Toast.LENGTH_SHORT).show();
    }
  • Add the code for reading from the “SharedPreferences” file to the “retrieve()” method.
    public void retrieve(View view) {
    
        SharedPreferences sharedPreferences = getSharedPreferences(STORAGE_NAME, Context.MODE_PRIVATE);
    
        email = sharedPreferences.getString("email", "");
        gender = sharedPreferences.getString("gender", "");
        hobbies = sharedPreferences.getString("hobbies", "");
        zodiac = sharedPreferences.getString("zodiac", "");
    
        setupUI();
    }

Testing 1, 2, 3, …

Launch the app on a real device or an AVD, you should see the “Shared  Preferences” page shown in Figure 1. On this page, enter an email, make some selections, and then click the “Save Me” button to save the input values to the “SharedPreferences” storage. Navigate away from the app, then navigate back to the “Shared  Preferences” page again, click the “Get Me” button to retrieve and display the previously saved values. If you make changes on the “Shared Preferences” page, then click on the “Save Me” button without saving the changes, it will revert back to the saved values. It should work. Give yourself a pat on the back.

Homework

Do not stop here! Challenge yourself to add a delete button and the code to the “SharedPreferencesActivity”  to delete all values from the shared preferences that you have saved. I shall leave it as your homework.

Follow-up

Congratulation! You have completed an app that handles different input types and stores the input data on shared preferences storage. I hope you will attempt the homework provided in this article as it will help to enhance your knowledge and enrich your learning experience.

Besides shared preferences, Android also provides other storage types such as internal storage, external storage, and SQLite database. To learn more, you may pick up my e-book on Handling Input and Storage on Android.

Download

Android Input and Shared Preferences Source

Tagged with: , ,

Speak Your Mind