From 779de5c040ab53e0dba9f7a21a236209a376f548 Mon Sep 17 00:00:00 2001 From: Scott Main Date: Thu, 22 Apr 2010 12:30:25 -0700 Subject: [PATCH] docs: rewrite information about using shared preferences, internal and external storage (including new apis), and sqlite databases. Change-Id: Ib951f14764759a04beca7b24767fb1e927245ebd --- docs/html/guide/topics/data/data-storage.jd | 504 +++++++++++++++----- 1 file changed, 381 insertions(+), 123 deletions(-) diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd index 0a1ee02635f44..52f1353db7ff8 100644 --- a/docs/html/guide/topics/data/data-storage.jd +++ b/docs/html/guide/topics/data/data-storage.jd @@ -7,18 +7,19 @@ page.title=Data Storage

Storage quickview

In this document

    -
  1. Preferences
  2. -
  3. Files
  4. -
  5. Databases
  6. -
  7. Network
  8. +
  9. Using Shared Preferences
  10. +
  11. Using the Internal Storage
  12. +
  13. Using the External Storage
  14. +
  15. Using Databases
  16. +
  17. Using a Network Connection

See also

@@ -29,171 +30,428 @@ page.title=Data Storage -

-A typical desktop operating system provides a common file system that any -application can use to store files that can be read by other -applications (perhaps with some access control settings). Android uses a -different system: On Android, all application data (including files) are -private to that application. +

Android provides several options for you to save persistent application data. The solution you +choose depends on your specific needs, such as whether the data should be private to your +application or accessible to other applications (and the user) and how much space your data +requires.

-

-However, Android also provides a standard way for an application to expose -its private data to other applications — through content providers. -A content provider is an -optional component of an application that exposes read/write access to the -application's data, subject to whatever restrictions it might impose. -Content providers implement a standard syntax for requesting and modifying -data, and a standard mechanism for reading the returned data. Android supplies -a number of content providers for standard data types, such as image, audio, -and video files and personal contact information. For more information on -using content providers, see a separate document, -Content Providers. -

- -

-Whether or not you want to export your application's data to others, -you need a way to store it. Android provides the following four mechanisms -for storing and retrieving data: Preferences, -Files, Databases, and Network. +

Your data storage options are the following:

+ +
+
Shared Preferences
+
Store private primitive data in key-value pairs.
+
Internal Storage
+
Store private data on the device memory.
+
External Storage
+
Store public data on the shared external storage.
+
SQLite Databases
+
Store structured data in a private database.
+
Network Connection
+
Store data on the web with your own network server.
+
+ +

Android provides a way for you to expose even your private data to other applications +— with a content +provider. A content provider is an optional component that exposes read/write access to +your application data, subject to whatever restrictions you want to impose. For more information +about using content providers, see the +Content Providers +documentation.

-

Preferences

-

Preferences is a lightweight mechanism to store and retrieve key-value pairs of primitive -data types. It is typically used to store application preferences, such as a -default greeting or a text font to be loaded whenever the application is started. Call -{@link android.content.Context#getSharedPreferences(java.lang.String,int) -Context.getSharedPreferences()} to read and write values. Assign a name to -your set of preferences if you want to share them with other components in the same -application, or use {@link android.app.Activity#getPreferences(int) -Activity.getPreferences()} with no name to keep them private to the calling -activity. You cannot share preferences across applications (except by using a -content provider). -

+ + +

Using Shared Preferences

+ +

The {@link android.content.SharedPreferences} class provides a general framework that allows you +to save and retrieve persistent key-value pairs of primitive data types. You can use {@link +android.content.SharedPreferences} to save any primitive data: booleans, floats, ints, longs, and +strings. This data will persist across user sessions (even if your application is killed).

+ + + +

To get a {@link android.content.SharedPreferences} object for your application, use one of +two methods:

+ + +

To write values:

+
    +
  1. Call {@link android.content.SharedPreferences#edit()} to get a {@link +android.content.SharedPreferences.Editor}.
  2. +
  3. Add values with methods such as {@link +android.content.SharedPreferences.Editor#putBoolean(String,boolean) putBoolean()} and {@link +android.content.SharedPreferences.Editor#putString(String,String) putString()}.
  4. +
  5. Commit the new values with {@link android.content.SharedPreferences.Editor#commit()}
  6. +
+ +

To read values, use {@link android.content.SharedPreferences} methods such as {@link +android.content.SharedPreferences#getBoolean(String,boolean) getBoolean()} and {@link +android.content.SharedPreferences#getString(String,String) getString()}.

-Here is an example of setting user preferences for silent keypress mode for a +Here is an example that saves a preference for silent keypress mode in a calculator:

-import android.app.Activity;
-import android.content.SharedPreferences;
-
 public class Calc extends Activity {
-public static final String PREFS_NAME = "MyPrefsFile";
-    . . .      
+    public static final String PREFS_NAME = "MyPrefsFile";
 
     @Override
     protected void onCreate(Bundle state){         
        super.onCreate(state);
-    
-    . . .
-    
+       . . .
+
        // Restore preferences
        SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        boolean silent = settings.getBoolean("silentMode", false);
        setSilent(silent);
     }
-    
+
     @Override
     protected void onStop(){
        super.onStop();
-    
-      // Save user preferences. We need an Editor object to
-      // make changes. All objects are from android.context.Context
+
+      // We need an Editor object to make preference changes.
+      // All objects are from android.context.Context
       SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
       SharedPreferences.Editor editor = settings.edit();
       editor.putBoolean("silentMode", mSilentMode);
 
-      // Don't forget to commit your edits!!!
+      // Commit the edits!
       editor.commit();
     }
 }
 
-

Files

-

You can store files directly on the mobile device or on a removable -storage medium. By default, other applications cannot access these files. + + + +

Using the Internal Storage

+ +

You can save files directly on the device's internal storage. By default, files saved +to the internal storage are private to your application and other applications cannot access +them (nor can the user). When the user uninstalls your application, these files are removed.

+ +

To create and write a private file to the internal storage:

+ +
    +
  1. Call {@link android.content.Context#openFileOutput(String,int) openFileOutput()} with the +name of the file and the operating mode. This returns a {@link java.io.FileOutputStream}.
  2. +
  3. Write to the file with {@link java.io.FileOutputStream#write(byte[]) write()}.
  4. +
  5. Close the stream with {@link java.io.FileOutputStream#close()}.
  6. +
+ +

For example:

+ +
+String FILENAME = "hello_file";
+String string = "hello world!";
+
+FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
+fos.write(string.getBytes());
+fos.close();
+
+ +

{@link android.content.Context#MODE_PRIVATE} will create the file (or replace a file of +the same name) and make it private to your application. Other modes available are: {@link +android.content.Context#MODE_APPEND}, {@link +android.content.Context#MODE_WORLD_READABLE}, and {@link +android.content.Context#MODE_WORLD_WRITEABLE}.

+ +

To read a file from internal storage:

+ +
    +
  1. Call {@link android.content.Context#openFileInput openFileInput()} and pass it the +name of the file to read. This returns a {@link java.io.FileInputStream}.
  2. +
  3. Read bytes from the file with {@link java.io.FileInputStream#read(byte[],int,int) +read()}.
  4. +
  5. Then close the stream with {@link java.io.FileInputStream#close()}.
  6. +
+ +

Tip: If you want to save a static file in your application at +compile time, save the file in your project res/raw/ directory. You can open it with +{@link android.content.res.Resources#openRawResource(int) openRawResource()}, passing the {@code +R.raw.<filename>} resource ID. This method returns an {@link java.io.InputStream} +that you can use to read the file (but you cannot write to the original file).

-

-To read data from a file, call {@link android.content.Context#openFileInput -Context.openFileInput()} and pass it the local name and path of the file. -It returns a standard Java {@link java.io.FileInputStream} object. To write -to a file, call {@link android.content.Context#openFileOutput -Context.openFileOutput()} with the name and path. It returns a {@link -java.io.FileOutputStream} object. Calling these methods with name and path -strings from another application will not work; you can only access local -files. -

-

-If you have a static file to package with your application at compile time, -you can save the file in your project in res/raw/myDataFile, -and then open it with {@link -android.content.res.Resources#openRawResource(int) Resources.openRawResource -(R.raw.myDataFile)}. It returns an {@link java.io.InputStream} -object that you can use to read from the file. -

+

Saving cache files

-

Databases

-

The Android API contains support for creating and using SQLite databases. -Each database is private to the application that creates it. -

+

If you'd like to cache some data, rather than store it persistently, you should use {@link +android.content.Context#getCacheDir()} to open a {@link +java.io.File} that represents the internal directory where your application should save +temporary cache files.

-

-The {@link android.database.sqlite.SQLiteDatabase} object represents a database -and has methods for interacting with it — making queries and managing the -data. To create the database, call {@link -android.database.sqlite.SQLiteDatabase#create SQLiteDatabase.create()} -and also subclass {@link android.database.sqlite.SQLiteOpenHelper}. -

+

When the device is +low on internal storage space, Android may delete these cache files to recover space. However, you +should not rely on the system to clean up these files for you. You should always maintain the cache +files yourself and stay within a reasonable limit of space consumed, such as 1MB. When the user +uninstalls your application, these files are removed.

-

-As part of its support for the SQLite database system, Android exposes -database management functions that let you store complex collections of data -wrapped into useful objects. For example, Android defines a data type -for contact information; it consists of many fields including a first and last -name (strings), an address and phone numbers (also strings), a photo (bitmap -image), and much other information describing a person. -

-

-Android ships with the sqlite3 database tool, which enables you to browse -table contents, run SQL commands, and perform other useful functions on SQLite -databases. See Examine databases -(sqlite3) to learn how to run this program. -

+

Other useful methods

-

-All databases, SQLite and others, are stored on the device in -/data/data/package_name/databases. -

+
+
{@link android.content.Context#getFilesDir()}
+
Gets the absolute path to the filesystem directory where your internal files are saved.
+
{@link android.content.Context#getDir(String,int) getDir()}
+
Creates (or opens an existing) directory within your internal storage space.
+
{@link android.content.Context#deleteFile(String) deleteFile()}
+
Deletes a file saved on the internal storage.
+
{@link android.content.Context#fileList()}
+
Returns an array of files currently saved by your application.
+
-

-Discussion of how many tables to create, what fields they contain, and how -they are linked, is beyond the scope of this note, but Android does not -impose any limitations beyond the standard SQLite concepts. We do recommend + + + +

Using the External Storage

+ +

Every Android-compatible device supports a shared "external storage" that you can use to +save files. This can be a removable storage media (such as an SD card) or an internal +(non-removable) storage. Files saved to the external storage are world-readable and can +be modified by the user when they enable USB mass storage to transfer files on a computer.

+ +

Caution: External files can disappear if the user mounts the +external storage on a computer or removes the media, and there's no security enforced upon files you +save to the external storage. All applications can read and write files placed on the external +storage and the user can remove them.

+ + +

Checking media availability

+ +

Before you do any work with the external storage, you should always call {@link +android.os.Environment#getExternalStorageState()} to check whether the media is available. The +media might be mounted to a computer, missing, read-only, or in some other state. For example, +here's how you can check the availability:

+ +
+boolean mExternalStorageAvailable = false;
+boolean mExternalStorageWriteable = false;
+String state = Environment.getExternalStorageState();
+
+if (Environment.MEDIA_MOUNTED.equals(state)) {
+    // We can read and write the media
+    mExternalStorageAvailable = mExternalStorageWriteable = true;
+} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+    // We can only read the media
+    mExternalStorageAvailable = true;
+    mExternalStorageWriteable = false;
+} else {
+    // Something else is wrong. It may be one of many other states, but all we need
+    //  to know is we can neither read nor write
+    mExternalStorageAvailable = mExternalStorageWriteable = false;
+}
+
+ +

This example checks whether the external storage is available to read and write. The +{@link android.os.Environment#getExternalStorageState()} method returns other states that you +might want to check, such as whether the media is being shared (connected to a computer), is missing +entirely, has been removed badly, etc. You can use these to notify the user with more information +when your application needs to access the media.

+ + +

Accessing files on external storage

+ +

If you're using API Level 8 or greater, use {@link +android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} to open a {@link +java.io.File} that represents the external storage directory where you should save your +files. This method takes a type parameter that specifies the type of subdirectory you +want, such as {@link android.os.Environment#DIRECTORY_MUSIC} and +{@link android.os.Environment#DIRECTORY_RINGTONES} (pass null to receive +the root of your application's file directory). This method will create the +appropriate directory if necessary. By specifying the type of directory, you +ensure that the Android's media scanner will properly categorize your files in the system (for +example, ringtones are identified as ringtones and not music). If the user uninstalls your +application, this directory and all its contents will be deleted.

+ +

If you're using API Level 7 or lower, use {@link +android.os.Environment#getExternalStorageDirectory()}, to open a {@link +java.io.File} representing the root of the external storage. You should then write your data in the +following directory:

+
+/Android/data/<package_name>/files/
+
+

The {@code <package_name>} is your Java-style package name, such as "{@code +com.example.android.app}". If the user's device is running API Level 8 or greater and they +uninstall your application, this directory and all its contents will be deleted.

+ + + + + +

Saving files that should be shared

+ +

If you want to save files that are not specific to your application and that should not +be deleted when your application is uninstalled, save them to one of the public directories on the +external storage. These directories lay at the root of the external storage, such as {@code +Music/}, {@code Pictures/}, {@code Ringtones/}, and others.

+ +

In API Level 8 or greater, use {@link +android.os.Environment#getExternalStoragePublicDirectory(String) +getExternalStoragePublicDirectory()}, passing it the type of public directory you want, such as +{@link android.os.Environment#DIRECTORY_MUSIC}, {@link android.os.Environment#DIRECTORY_PICTURES}, +{@link android.os.Environment#DIRECTORY_RINGTONES}, or others. This method will create the +appropriate directory if necessary.

+ +

If you're using API Level 7 or lower, use {@link +android.os.Environment#getExternalStorageDirectory()} to open a {@link java.io.File} that represents +the root of the external storage, then save your shared files in one of the following +directories:

+ + + + +

Saving cache files

+ +

If you're using API Level 8 or greater, use {@link +android.content.Context#getExternalCacheDir()} to open a {@link java.io.File} that represents the +external storage directory where you should save cache files. If the user uninstalls your +application, these files will be automatically deleted. However, during the life of your +application, you should manage these cache files and remove those that aren't needed in order to +preserve file space.

+ +

If you're using API Level 7 or lower, use {@link +android.os.Environment#getExternalStorageDirectory()} to open a {@link java.io.File} that represents +the root of the external storage, then write your cache data in the following directory:

+
+/Android/data/<package_name>/cache/
+
+

The {@code <package_name>} is your Java-style package name, such as "{@code +com.example.android.app}".

+ + + +

Using Databases

+ +

Android provides full support for SQLite databases. +Any databases you create will be accessible by name to any +class in the application, but not outside the application.

+ +

The recommended method to create a new SQLite database is to create a subclass of {@link +android.database.sqlite.SQLiteOpenHelper} and override the {@link +android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) onCreate()} method, in which you +can execute a SQLite command to create tables in the database. For example:

+ +
+public class MyDbOpenHelper extends SQLiteOpenHelper {
+
+    private static final int DATABASE_VERSION = 2;
+    private static final String DICTIONARY_TABLE_NAME = "dictionary";
+    private static final String DICTIONARY_TABLE_CREATE =
+                "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +
+                KEY_WORD + " TEXT, " +
+                KEY_DEFINITION + " TEXT);";
+
+    DictionaryOpenHelper(Context context) {
+        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        db.execSQL(DICTIONARY_TABLE_CREATE);
+    }
+}
+
+ +

You can then get an instance of your {@link android.database.sqlite.SQLiteOpenHelper} +implementation using the constructor you've defined. To write to and read from the database, call +{@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase()} and {@link +android.database.sqlite.SQLiteOpenHelper#getReadableDatabase()}, respectively. These both return a +{@link android.database.sqlite.SQLiteDatabase} object that represents the database and +provides methods for SQLite operations.

+ + + +

You can execute SQLite queries using the {@link android.database.sqlite.SQLiteDatabase} +{@link +android.database.sqlite.SQLiteDatabase#query(boolean,String,String[],String,String[],String,String,String,String) +query()} methods, which accept various query parameters, such as the table to query, +the projection, selection, columns, grouping, and others. For complex queries, such as +those that require column aliases, you should use +{@link android.database.sqlite.SQLiteQueryBuilder}, which provides +several convienent methods for building queries.

+ +

Every SQLite query will return a {@link android.database.Cursor} that points to all the rows +found by the query. The {@link android.database.Cursor} is always the mechanism with which +you can navigate results from a database query and read rows and columns.

+ +

For sample apps that demonstrate how to use SQLite databases in Android, see the +Note Pad and +Searchable Dictionary +applications.

+ + +

Database debugging

+ +

The Android SDK includes a {@code sqlite3} database tool that allows you to browse +table contents, run SQL commands, and perform other useful functions on SQLite +databases. See Examining sqlite3 +databases from a remote shell to learn how to run this tool.

-

Network

-

You can also use the network to store and retrieve data (when it's available). -To do network operations, use the classes in the following packages:

+ + + +

Using a Network Connection

+ + + +

You can use the network (when it's available) to store and retrieve data on your own web-based +services. To do network operations, use classes in the following packages:

-