This chapter describes how to persist data in your Android applications. Persisting data is an important topic in application development because users typically expect to reuse data in the future. For Android, there are primarily three basic ways of persisting data:
The techniques discussed in this chapter enable applications to create and access their own private data. Chapter 8 shows you how to share data across applications.
Android provides the SharedPreferences object to help you save simple application data. For example, your application may have an option that enables users to specify the font size used in your application. In this case, your application needs to remember the size set by the user so that the size is set appropriately each time the app is opened. You have several options for saving this type of preference:
SharedPreferences object—The SharedPreferences object, however, saves data through the use of name/value pairs. For example, specify a name for the data you want to save, and then both it and its value will be saved automatically to an XML file.In the following Try It Out, you see how to use the SharedPreferences object to store application data. You also find out how the stored application data can be modified directly by the user through a special type of activity provided by the Android OS.
In the previous section, you saw how the PreferenceActivity class both enables developers to easily create preferences and enables users to modify them during runtime. To make use of these preferences in your application, you use the SharedPreferences class. The following Try It Out shows you how.
The SharedPreferences object enables you to store data that is best stored as name/value pairs—for example, user ID, birth date, gender, driver's license number, and so on. However, sometimes you might prefer to use the traditional file system to store your data. For example, you might want to store the text of poems you want to display in your applications. In Android, you can use the classes in the java.io package to do so.
The first way to save files in your Android application is to write to the device's internal storage. The following Try It Out demonstrates how to save a string entered by the user to the device's internal storage.
The previous section showed how you can save your files to the internal storage of your Android device. Sometimes, it would be useful to save them to external storage (such as an SD card) because of its larger capacity, as well as the capability to share the files easily with other users (by removing the SD card and passing it to somebody else). You can use the following steps to save files to external storage:
onClick() method of the Save button as shown in bold here:import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public void onClickSave(View view) {
String str = textBox.getText().toString();
try
{
//---SD Card Storage---
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File (sdCard.getAbsolutePath() +
"/MyFiles");
directory.mkdirs();
File file = new File(directory, "textfile.txt");
FileOutputStream fOut = new FileOutputStream(file);
/*
FileOutputStream fOut =
openFileOutput("textfile.txt",
MODE_WORLD_READABLE);
*/
OutputStreamWriter osw = new
OutputStreamWriter(fOut);
//---write the string to the file---
osw.write(str);
osw.flush();
osw.close();
//---display file saved message---
Toast.makeText(getBaseContext(),
"File saved successfully!",
Toast.LENGTH_SHORT).show();
//---clears the EditText---
textBox.setText("");
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
getExternalStorageDirectory() method to return the full path to the external storage. Typically, it should return the “/sdcard” path for a real device, and “/mnt/sdcard” for an Android emulator. However, you should never try to hardcode the path to the SD card, as manufacturers may choose to assign a different path name to the SD card. Be sure to use the getExternalStorageDirectory() method to return the full path to the SD card.MyFiles in the SD card.onClickLoad() method for the Load button: public void onClickLoad(View view) {
try
{
//---SD Storage---
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File (sdCard.getAbsolutePath() +
"/MyFiles");
File file = new File(directory, "textfile.txt");
FileInputStream fIn = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fIn);
/*
FileInputStream fIn =
openFileInput("textfile.txt");
InputStreamReader isr = new
InputStreamReader(fIn);
*/
char[] inputBuffer = new char[READ_BLOCK_SIZE];
String s = "";
int charRead;
while ((charRead = isr.read(inputBuffer))>0)
{
//---convert the chars to a String---
String readString =
String.copyValueOf(inputBuffer, 0,
charRead);
s += readString;
inputBuffer = new char[READ_BLOCK_SIZE];
}
//---set the EditText to the text that has been
// read---
textBox.setText(s);
Toast.makeText(getBaseContext(),
"File loaded successfully!",
Toast.LENGTH_SHORT).show();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
WRITE_EXTERNAL_STORAGE permission in your AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jfdimarzio.Files"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="14"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".FilesActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
The previous sections described three main ways to save data in your Android applications: the SharedPreferences object, internal storage, and external storage. Which one should you use in your applications? Here are some guidelines:
SharedPreferences object. For example, if you want to store user preference data such as username, background color, date of birth, or last login date, then the SharedPreferences object is the ideal way to store this data. Moreover, you don't really have to do much to store data this way. Simply use the SharedPreferences object to store and retrieve it.So far, all the techniques you have seen are useful for saving simple sets of data. For saving relational data, using a database is much more efficient. For example, if you want to store the test results of all the students in a school, it is much more efficient to use a database to represent them because you can use database querying to retrieve the results of specific students. Moreover, using databases enables you to enforce data integrity by specifying the relationships between different sets of data.
Android uses the SQLite database system. The database that you create for an application is only accessible to itself; other applications will not be able to access it.
In this section, you find out how to programmatically create a SQLite database in your Android application. For Android, the SQLite database that you create programmatically in an application is always stored in the /data/data/<package_name>/databases folder.
A good practice for dealing with databases is to create a helper class to encapsulate all the complexities of accessing the data so that it is transparent to the calling code. For this section, you create a helper class called DBAdapter, which creates, opens, closes, and uses a SQLite database.
In this example, you are going to create a database named MyDB containing one table named contacts. This table has three columns: _id, name, and email.
With the DBAdapter helper class created, you are now ready to use the database. In the following sections, you will learn how to perform the regular CRUD (create, read, update and delete) operations commonly associated with databases.
The following Try It Out demonstrates how you can add a contact to the table.
To retrieve all the contacts in the contacts table, use the getAllContacts() method of the DBAdapter class, as the following Try It Out shows.
To retrieve a single contact using its ID, call the getContact() method of the DBAdapter class, as the following Try It Out shows.
To update a particular contact, call the updateContact() method in the DBAdapter class by passing the ID of the contact you want to update, as the following Try It Out shows.
To delete a contact, use the deleteContact() method in the DBAdapter class by passing the ID of the contact you want to update, as the following Try It Out shows.
Sometimes, after creating and using the database, you might need to add additional tables, change the schema of the database, or add columns to your tables. In this case, you need to migrate your existing data from the old database to a newer one.
To upgrade the database, change the DATABASE_VERSION constant to a value higher than the previous one. For example, if its previous value was 1, change it to 2:
public class DBAdapter {
static final String KEY_ROWID = "_id";
static final String KEY_NAME = "name";
static final String KEY_EMAIL = "email";
static final String TAG = "DBAdapter";
static final String DATABASE_NAME = "MyDB";
static final String DATABASE_TABLE = "contacts";
static final int DATABASE_VERSION = 2;
When you run the application one more time, you see the following message in the logcat window of Android Studio:
DBAdapter(8705): Upgrading database from version 1 to 2, which
will destroy all old data
For simplicity, simply drop the existing table and create a new one. In real life, you usually back up your existing table and then copy it over to the new table.
In this chapter, you were introduced to the different ways to save persistent data to your Android device. For simple unstructured data, using the SharedPreferences object is the ideal solution. If you need to store bulk data then consider using the traditional file system. Finally, for structured data, it is more efficient to store it in a relational database management system. For this, Android provides the SQLite database, which you can access easily using the APIs exposed.
Note that for the SharedPreferences object and the SQLite database, the data is accessible only by the application that creates it. In other words, it is not shareable. If you need to share data among different applications, you need to create a content provider. Content providers are discussed in more detail in Chapter 8.
You can find answers to the exercises in the appendix.
| Topic | Key Concepts |
| Saving simple user data | Use the SharedPreferences object. |
| Sharing data among activities in the same application | Use the getSharedPreferences() method. |
| Saving to a file | Use the FileOutputStream and OutputStreamReader classes. |
| Reading from a file | Use the FileInputStream and InputStreamReader classes. |
| Saving to external storage | Use the getExternalStorageDirectory() method to return the path to the external storage. |
Accessing files in the res/raw folder |
Use the openRawResource() method in the Resources object (obtained via the getResources() method). |
| Creating a database helper class | Extend the SQLiteOpenHelper class. |