docs: android training - Data Storage
Change-Id: I9579a7eb04cb39d3b457dde390b6b2a7b240a429
This commit is contained in:
@ -232,7 +232,12 @@ save files. This can be a removable storage media (such as an SD card) or an int
|
|||||||
(non-removable) storage. Files saved to the external storage are world-readable and can
|
(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.</p>
|
be modified by the user when they enable USB mass storage to transfer files on a computer.</p>
|
||||||
|
|
||||||
<p class="caution"><strong>Caution:</strong> External files can disappear if the user mounts the
|
<p>It's possible that a device using a partition of the
|
||||||
|
internal storage for the external storage may also offer an SD card slot. In this case,
|
||||||
|
the SD card is <em>not</em> part of the external storage and your app cannot access it (the extra
|
||||||
|
storage is intended only for user-provided media that the system scans).</p>
|
||||||
|
|
||||||
|
<p class="caution"><strong>Caution:</strong> External storage can become unavailable if the user mounts the
|
||||||
external storage on a computer or removes the media, and there's no security enforced upon files you
|
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
|
save to the external storage. All applications can read and write files placed on the external
|
||||||
storage and the user can remove them.</p>
|
storage and the user can remove them.</p>
|
||||||
|
322
docs/html/training/basics/data-storage/databases.jd
Normal file
322
docs/html/training/basics/data-storage/databases.jd
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
page.title=Saving Data in SQL Databases
|
||||||
|
parent.title=Data Storage
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
previous.title=Saving Data in Files
|
||||||
|
previous.link=files.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>This lesson teaches you to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#DefineContract">Define a Schema and Contract</a></li>
|
||||||
|
<li><a href="#DbHelper">Create a Database Using a SQL Helper</a></li>
|
||||||
|
<li><a href="#WriteDbRow">Put Information into a Database</a></li>
|
||||||
|
<li><a href="#ReadDbRow">Read Information from a Database</a></li>
|
||||||
|
<li><a href="#DeleteDbRow">Delete Information from a Database</a></li>
|
||||||
|
<li><a href="#UpdateDbRow">Update a Database</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/data/data-storage.html#db">Using Databases</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<h2>Try it out</h2>
|
||||||
|
|
||||||
|
<div class="download-box">
|
||||||
|
<a href="{@docRoot}shareables/training/Sample.zip" class="button">Download the sample</a>
|
||||||
|
<p class="filename">Sample.zip</p>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Saving data to a database is ideal for repeating or structured data,
|
||||||
|
such as contact information. This class assumes that you are
|
||||||
|
familiar with SQL databases in general and helps you get started with
|
||||||
|
SQLite databases on Android. The APIs you'll need to use a database
|
||||||
|
on Android are available in the {@link android.database.sqlite} package.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="DefineContract">Define a Schema and Contract</h2>
|
||||||
|
|
||||||
|
<p>One of the main principles of SQL databases is the schema: a formal
|
||||||
|
declaration of how the database is organized. The schema is reflected in the SQL
|
||||||
|
statements that you use to create your database. You may find it helpful to
|
||||||
|
create a companion class, known as a <em>contract</em> class, which explicitly specifies
|
||||||
|
the layout of your schema in a systematic and self-documenting way.</p>
|
||||||
|
|
||||||
|
<p>A contract class is a container for constants that define names for URIs,
|
||||||
|
tables, and columns. The contract class allows you to use the same constants
|
||||||
|
across all the other classes in the same package. This lets you change a column
|
||||||
|
name in one place and have it propagate throughout your code.</p>
|
||||||
|
|
||||||
|
<p>A good way to organize a contract class is to put definitions that are
|
||||||
|
global to your whole database in the root level of the class. Then create an inner
|
||||||
|
class for each table that enumerates its columns.</p>
|
||||||
|
|
||||||
|
<p class="note"><strong>Note:</strong> By implementing the {@link
|
||||||
|
android.provider.BaseColumns} interface, your inner class can inherit a primary
|
||||||
|
key field called {@code _ID} that some Android classes such as cursor adaptors
|
||||||
|
will expect it to have. It's not required, but this can help your database
|
||||||
|
work harmoniously with the Android framework.</p>
|
||||||
|
|
||||||
|
<p>For example, this snippet defines the table name and column names for a
|
||||||
|
single table:</p>
|
||||||
|
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public static abstract class FeedEntry implements BaseColumns {
|
||||||
|
public static final String TABLE_NAME = "entry";
|
||||||
|
public static final String COLUMN_NAME_ENTRY_ID = "entryid";
|
||||||
|
public static final String COLUMN_NAME_TITLE = "title";
|
||||||
|
public static final String COLUMN_NAME_SUBTITLE = "subtitle";
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<p>To prevent someone from accidentally instantiating the contract class, give
|
||||||
|
it an empty constructor. </p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
// Prevents the FeedReaderContract class from being instantiated.
|
||||||
|
private FeedReaderContract() {}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="DbHelper">Create a Database Using a SQL Helper</h2>
|
||||||
|
|
||||||
|
<p>Once you have defined how your database looks, you should implement methods
|
||||||
|
that create and maintain the database and tables. Here are some typical
|
||||||
|
statements that create and delete a table:</P>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private static final String TEXT_TYPE = " TEXT";
|
||||||
|
private static final String COMMA_SEP = ",";
|
||||||
|
private static final String SQL_CREATE_ENTRIES =
|
||||||
|
"CREATE TABLE " + FeedReaderContract.FeedEntry.TABLE_NAME + " (" +
|
||||||
|
FeedReaderContract.FeedEntry._ID + " INTEGER PRIMARY KEY," +
|
||||||
|
FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
|
||||||
|
FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
|
||||||
|
... // Any other options for the CREATE command
|
||||||
|
" )";
|
||||||
|
|
||||||
|
private static final String SQL_DELETE_ENTRIES =
|
||||||
|
"DROP TABLE IF EXISTS " + TABLE_NAME_ENTRIES;
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Just like files that you save on the device's <a
|
||||||
|
href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal
|
||||||
|
storage</a>, Android stores your database in private disk space that's associated
|
||||||
|
application. Your data is secure, because by default this area is not
|
||||||
|
accessible to other applications.</p>
|
||||||
|
|
||||||
|
<p>A useful set of APIs is available in the {@link
|
||||||
|
android.database.sqlite.SQLiteOpenHelper} class.
|
||||||
|
When you use this class to obtain references to your database, the system
|
||||||
|
performs the potentially
|
||||||
|
long-running operations of creating and updating the database only when
|
||||||
|
needed and <em>not during app startup</em>. All you need to do is call
|
||||||
|
{@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} or
|
||||||
|
{@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase}.</p>
|
||||||
|
|
||||||
|
<p class="note"><strong>Note:</strong> Because they can be long-running,
|
||||||
|
be sure that you call {@link
|
||||||
|
android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} or {@link
|
||||||
|
android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} in a background thread,
|
||||||
|
such as with {@link android.os.AsyncTask} or {@link android.app.IntentService}.</p>
|
||||||
|
|
||||||
|
<p>To use {@link android.database.sqlite.SQLiteOpenHelper}, create a subclass that
|
||||||
|
overrides the {@link
|
||||||
|
android.database.sqlite.SQLiteOpenHelper#onCreate onCreate()}, {@link
|
||||||
|
android.database.sqlite.SQLiteOpenHelper#onUpgrade onUpgrade()} and {@link
|
||||||
|
android.database.sqlite.SQLiteOpenHelper#onOpen onOpen()} callback methods. You may also
|
||||||
|
want to implement {@link android.database.sqlite.SQLiteOpenHelper#onDowngrade onDowngrade()},
|
||||||
|
but it's not required.</p>
|
||||||
|
|
||||||
|
<p>For example, here's an implementation of {@link
|
||||||
|
android.database.sqlite.SQLiteOpenHelper} that uses some of the commands shown above:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public class FeedReaderDbHelper extends SQLiteOpenHelper {
|
||||||
|
// If you change the database schema, you must increment the database version.
|
||||||
|
public static final int DATABASE_VERSION = 1;
|
||||||
|
public static final String DATABASE_NAME = "FeedReader.db";
|
||||||
|
|
||||||
|
public FeedReaderDbHelper(Context context) {
|
||||||
|
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||||
|
}
|
||||||
|
public void onCreate(SQLiteDatabase db) {
|
||||||
|
db.execSQL(SQL_CREATE_ENTRIES);
|
||||||
|
}
|
||||||
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
// This database is only a cache for online data, so its upgrade policy is
|
||||||
|
// to simply to discard the data and start over
|
||||||
|
db.execSQL(SQL_DELETE_ENTRIES);
|
||||||
|
onCreate(db);
|
||||||
|
}
|
||||||
|
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
onUpgrade(db, oldVersion, newVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>To access your database, instantiate your subclass of {@link
|
||||||
|
android.database.sqlite.SQLiteOpenHelper}:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="WriteDbRow">Put Information into a Database</h2>
|
||||||
|
|
||||||
|
<p>Insert data into the database by passing a {@link android.content.ContentValues}
|
||||||
|
object to the {@link android.database.sqlite.SQLiteDatabase#insert insert()} method:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
// Gets the data repository in write mode
|
||||||
|
SQLiteDatabase db = mDbHelper.getWritableDatabase();
|
||||||
|
|
||||||
|
// Create a new map of values, where column names are the keys
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID, id);
|
||||||
|
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);
|
||||||
|
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT, content);
|
||||||
|
|
||||||
|
// Insert the new row, returning the primary key value of the new row
|
||||||
|
long newRowId;
|
||||||
|
newRowId = db.insert(
|
||||||
|
FeedReaderContract.FeedEntry.TABLE_NAME,
|
||||||
|
FeedReaderContract.FeedEntry.COLUMN_NAME_NULLABLE,
|
||||||
|
values);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>The first argument for {@link android.database.sqlite.SQLiteDatabase#insert insert()}
|
||||||
|
is simply the table name. The second argument provides
|
||||||
|
the name of a column in which the framework can insert NULL in the event that the
|
||||||
|
{@link android.content.ContentValues} is empty (if you instead set this to {@code "null"},
|
||||||
|
then the framework will not insert a row when there are no values).</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="ReadDbRow">Read Information from a Database</h2>
|
||||||
|
|
||||||
|
<p>To read from a database, use the {@link android.database.sqlite.SQLiteDatabase#query query()}
|
||||||
|
method, passing it your selection criteria and desired columns.
|
||||||
|
The method combines elements of {@link android.database.sqlite.SQLiteDatabase#insert insert()}
|
||||||
|
and {@link android.database.sqlite.SQLiteDatabase#update update()}, except the column list
|
||||||
|
defines the data you want to fetch, rather than the data to insert. The results of the query
|
||||||
|
are returned to you in a {@link android.database.Cursor} object.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
SQLiteDatabase db = mDbHelper.getReadableDatabase();
|
||||||
|
|
||||||
|
// Define a <em>projection</em> that specifies which columns from the database
|
||||||
|
// you will actually use after this query.
|
||||||
|
String[] projection = {
|
||||||
|
FeedReaderContract.FeedEntry._ID,
|
||||||
|
FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE,
|
||||||
|
FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED,
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
// How you want the results sorted in the resulting Cursor
|
||||||
|
String sortOrder =
|
||||||
|
FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED + " DESC";
|
||||||
|
|
||||||
|
Cursor c = db.query(
|
||||||
|
FeedReaderContract.FeedEntry.TABLE_NAME, // The table to query
|
||||||
|
projection, // The columns to return
|
||||||
|
selection, // The columns for the WHERE clause
|
||||||
|
selectionArgs, // The values for the WHERE clause
|
||||||
|
null, // don't group the rows
|
||||||
|
null, // don't filter by row groups
|
||||||
|
sortOrder // The sort order
|
||||||
|
);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>To look at a row in the cursor, use one of the {@link android.database.Cursor} move
|
||||||
|
methods, which you must always call before you begin reading values. Generally, you should start
|
||||||
|
by calling {@link android.database.Cursor#moveToFirst}, which places the "read position" on the
|
||||||
|
first entry in the results. For each row, you can read a column's value by calling one of the
|
||||||
|
{@link android.database.Cursor} get methods, such as {@link android.database.Cursor#getString
|
||||||
|
getString()} or {@link android.database.Cursor#getLong getLong()}. For each of the get methods,
|
||||||
|
you must pass the index position of the column you desire, which you can get by calling
|
||||||
|
{@link android.database.Cursor#getColumnIndex getColumnIndex()} or
|
||||||
|
{@link android.database.Cursor#getColumnIndexOrThrow getColumnIndexOrThrow()}.
|
||||||
|
For example:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
cursor.moveToFirst();
|
||||||
|
long itemId = cursor.getLong(
|
||||||
|
cursor.getColumnIndexOrThrow(FeedReaderContract.FeedEntry._ID)
|
||||||
|
);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="DeleteDbRow">Delete Information from a Database</h2>
|
||||||
|
|
||||||
|
<p>To delete rows from a table, you need to provide selection criteria that
|
||||||
|
identify the rows. The database API provides a mechanism for creating selection
|
||||||
|
criteria that protects against SQL injection. The mechanism divides the
|
||||||
|
selection specification into a selection clause and selection arguments. The
|
||||||
|
clause defines the columns to look at, and also allows you to combine column
|
||||||
|
tests. The arguments are values to test against that are bound into the clause.
|
||||||
|
Because the result isn't handled the same as a regular SQL statement, it is
|
||||||
|
immune to SQL injection.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
// Define 'where' part of query.
|
||||||
|
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
|
||||||
|
// Specify arguments in placeholder order.
|
||||||
|
String[] selelectionArgs = { String.valueOf(rowId) };
|
||||||
|
// Issue SQL statement.
|
||||||
|
db.delete(table_name, mySelection, selectionArgs);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="UpdateDbRow">Update a Database</h2>
|
||||||
|
|
||||||
|
<p>When you need to modify a subset of your database values, use the {@link
|
||||||
|
android.database.sqlite.SQLiteDatabase#update update()} method.</p>
|
||||||
|
|
||||||
|
<p>Updating the table combines the content values syntax of {@link
|
||||||
|
android.database.sqlite.SQLiteDatabase#insert insert()} with the {@code where} syntax
|
||||||
|
of {@link android.database.sqlite.SQLiteDatabase#delete delete()}.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
SQLiteDatabase db = mDbHelper.getReadableDatabase();
|
||||||
|
|
||||||
|
// New value for one column
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);
|
||||||
|
|
||||||
|
// Which row to update, based on the ID
|
||||||
|
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
|
||||||
|
String[] selelectionArgs = { String.valueOf(rowId) };
|
||||||
|
|
||||||
|
int count = db.update(
|
||||||
|
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
|
||||||
|
values,
|
||||||
|
selection,
|
||||||
|
selectionArgs);
|
||||||
|
</pre>
|
||||||
|
|
382
docs/html/training/basics/data-storage/files.jd
Normal file
382
docs/html/training/basics/data-storage/files.jd
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
page.title=Saving Files
|
||||||
|
parent.title=Data Storage
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>This lesson teaches you to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#InternalVsExternalStorage">Choose Internal or External Storage</a></li>
|
||||||
|
<li><a href="#GetWritePermission">Obtain Permissions for External Storage</a></li>
|
||||||
|
<li><a href="#WriteInternalStorage">Save a File on Internal Storage</a></li>
|
||||||
|
<li><a href="#WriteExternalStorage">Save a File on External Storage</a></li>
|
||||||
|
<li><a href="#GetFreeSpace">Query Free Space</a></li>
|
||||||
|
<li><a href="#DeleteFile">Delete a File</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">Using the Internal
|
||||||
|
Storage</a></li>
|
||||||
|
<li><a href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">Using the External
|
||||||
|
Storage</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>Android uses a file system that's
|
||||||
|
similar to disk-based file systems on other platforms. This lesson describes
|
||||||
|
how to work with the Android file system to read and write files with the {@link java.io.File}
|
||||||
|
APIs.</p>
|
||||||
|
|
||||||
|
<p>A {@link java.io.File} object is suited to reading or writing large amounts of data in
|
||||||
|
start-to-finish order without skipping around. For example, it's good for image files or
|
||||||
|
anything exchanged over a network.</p>
|
||||||
|
|
||||||
|
<p>This lesson shows how to perform basic file-related tasks in your app.
|
||||||
|
The lesson assumes that you are familiar with the basics of the Linux file system and the
|
||||||
|
standard file input/output APIs in {@link java.io}.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="InternalVsExternalStorage">Choose Internal or External Storage</h2>
|
||||||
|
|
||||||
|
<p>All Android devices have two file storage areas: "internal" and "external" storage. These names
|
||||||
|
come from the early days of Android, when most devices offered built-in non-volatile memory
|
||||||
|
(internal storage), plus a removable storage medium such as a micro SD card (external storage).
|
||||||
|
Some devices divide the permanent storage space into "internal" and "external" partitions, so even
|
||||||
|
without a removable storage medium, there are always two storage spaces and
|
||||||
|
the API behavior is the same whether the external storage is removable or not.
|
||||||
|
The following lists summarize the facts about each storage space.</p>
|
||||||
|
|
||||||
|
<div class="col-5" style="margin-left:0">
|
||||||
|
<p><b>Internal storage:</b></p>
|
||||||
|
<ul>
|
||||||
|
<li>It's always available.</li>
|
||||||
|
<li>Files saved here are accessible by only your app by default.</li>
|
||||||
|
<li>When the user uninstalls your app, the system removes all your app's files from
|
||||||
|
internal storage.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Internal storage is best when you want to be sure that neither the user nor other apps can
|
||||||
|
access your files.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-7" style="margin-right:0">
|
||||||
|
<p><b>External storage:</b></p>
|
||||||
|
<ul>
|
||||||
|
<li>It's not always available, because the user can mount the external storage as USB storage
|
||||||
|
and in some cases remove it from the device.</li>
|
||||||
|
<li>It's world-readable, so
|
||||||
|
files saved here may be read outside of your control.</li>
|
||||||
|
<li>When the user uninstalls your app, the system removes your app's files from here
|
||||||
|
only if you save them in the directory from {@link android.content.Context#getExternalFilesDir
|
||||||
|
getExternalFilesDir()}.</li>
|
||||||
|
</ul>
|
||||||
|
<p>External storage is the best
|
||||||
|
place for files that don't require access restrictions and for files that you want to share
|
||||||
|
with other apps or allow the user to access with a computer.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p class="note" style="clear:both">
|
||||||
|
<strong>Tip:</strong> Although apps are installed onto the internal storage by
|
||||||
|
default, you can specify the <a
|
||||||
|
href="{@docRoot}guide/topics/manifest/manifest-element.html#install">{@code
|
||||||
|
android:installLocation}</a> attribute in your manifest so your app may
|
||||||
|
be installed on external storage. Users appreciate this option when the APK size is very large and
|
||||||
|
they have an external storage space that's larger than the internal storage. For more
|
||||||
|
information, see <a
|
||||||
|
href="{@docRoot}guide/topics/data/install-location.html">App Install Location</a>.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="GetWritePermission">Obtain Permissions for External Storage</h2>
|
||||||
|
|
||||||
|
<p>To write to the external storage, you must request the
|
||||||
|
{@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission in your <a
|
||||||
|
href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest file</a>:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<manifest ...>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
...
|
||||||
|
</manifest>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<div class="caution"><p><strong>Caution:</strong>
|
||||||
|
Currently, all apps have the ability to read the external storage
|
||||||
|
without a special permission. However, this will change in a future release. If your app needs
|
||||||
|
to read the external storage (but not write to it), then you will need to declare the {@link
|
||||||
|
android.Manifest.permission#READ_EXTERNAL_STORAGE} permission. To ensure that your app continues
|
||||||
|
to work as expected, you should declare this permission now, before the change takes effect.</p>
|
||||||
|
<pre>
|
||||||
|
<manifest ...>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
...
|
||||||
|
</manifest>
|
||||||
|
</pre>
|
||||||
|
<p>However, if your app uses the {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
|
||||||
|
permission, then it implicitly has permission to read the external storage as well.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>You don’t need any permissions to save files on the internal
|
||||||
|
storage. Your application always has permission to read and
|
||||||
|
write files in its internal storage directory.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="WriteInternalStorage">Save a File on Internal Storage</h2>
|
||||||
|
|
||||||
|
<p>When saving a file to internal storage, you can acquire the appropriate directory as a
|
||||||
|
{@link java.io.File} by calling one of two methods:</p>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>{@link android.content.Context#getFilesDir}</dt>
|
||||||
|
<dd>Returns a {@link java.io.File} representing an internal directory for your app.</dd>
|
||||||
|
<dt>{@link android.content.Context#getCacheDir}</dt>
|
||||||
|
<dd>Returns a {@link java.io.File} representing an internal directory for your app's temporary
|
||||||
|
cache files. Be sure to delete each file once it is no
|
||||||
|
longer needed and implement a reasonable size limit for the amount of memory you use at any given
|
||||||
|
time, such as 1MB. If the system begins running low on storage, it may delete your cache files
|
||||||
|
without warning.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<p>To create a new file in one of these directories, you can use the {@link
|
||||||
|
java.io.File#File(File,String) File()} constructor, passing the {@link java.io.File} provided by one
|
||||||
|
of the above methods that specifies your internal storage directory. For example:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
File file = new File(context.getFilesDir(), filename);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Alternatively, you can call {@link
|
||||||
|
android.content.Context#openFileOutput openFileOutput()} to get a {@link java.io.FileOutputStream}
|
||||||
|
that writes to a file in your internal directory. For example, here's
|
||||||
|
how to write some text to a file:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
String filename = "myfile";
|
||||||
|
String string = "Hello world!";
|
||||||
|
FileOutputStream outputStream;
|
||||||
|
|
||||||
|
try {
|
||||||
|
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
|
||||||
|
outputStream.write(string.getBytes());
|
||||||
|
outputStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Or, if you need to cache some files, you should instead use {@link
|
||||||
|
java.io.File#createTempFile createTempFile()}. For example, the following method extracts the
|
||||||
|
file name from a {@link java.net.URL} and creates a file with that name
|
||||||
|
in your app's internal cache directory:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public File getTempFile(Context context, String url) {
|
||||||
|
File file;
|
||||||
|
try {
|
||||||
|
String fileName = Uri.parse(url).getLastPathSegment();
|
||||||
|
file = File.createTempFile(fileName, null, context.getCacheDir());
|
||||||
|
catch (IOException e) {
|
||||||
|
// Error while creating file
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p class="note"><strong>Note:</strong>
|
||||||
|
Your app's internal storage directory is specified
|
||||||
|
by your app's package name in a special location of the Android file system.
|
||||||
|
Technically, another app can read your internal files if you set
|
||||||
|
the file mode to be readable. However, the other app would also need to know your app package
|
||||||
|
name and file names. Other apps cannot browse your internal directories and do not have
|
||||||
|
read or write access unless you explicitly set the files to be readable or writable. So as long
|
||||||
|
as you use {@link android.content.Context#MODE_PRIVATE} for your files on the internal storage,
|
||||||
|
they are never accessible to other apps.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="WriteExternalStorage">Save a File on External Storage</h2>
|
||||||
|
|
||||||
|
<p>Because the external storage may be unavailable—such as when the user has mounted the
|
||||||
|
storage to a PC or has removed the SD card that provides the external storage—you
|
||||||
|
should always verify that the volume is available before accessing it. You can query the external
|
||||||
|
storage state by calling {@link android.os.Environment#getExternalStorageState}. If the returned
|
||||||
|
state is equal to {@link android.os.Environment#MEDIA_MOUNTED}, then you can read and
|
||||||
|
write your files. For example, the following methods are useful to determine the storage
|
||||||
|
availability:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
/* Checks if external storage is available for read and write */
|
||||||
|
public boolean isExternalStorageWritable() {
|
||||||
|
String state = Environment.getExternalStorageState();
|
||||||
|
if (Environment.MEDIA_MOUNTED.equals(state)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checks if external storage is available to at least read */
|
||||||
|
public boolean isExternalStorageReadable() {
|
||||||
|
String state = Environment.getExternalStorageState();
|
||||||
|
if (Environment.MEDIA_MOUNTED.equals(state) ||
|
||||||
|
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Although the external storage is modifiable by the user and other apps, there are two
|
||||||
|
categories of files you might save here:</p>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>Public files</dt>
|
||||||
|
<dd>Files that
|
||||||
|
should be freely available to other apps and to the user. When the user uninstalls your app,
|
||||||
|
these files should remain available to the user.
|
||||||
|
<p>For example, photos captured by your app or other downloaded files.</p>
|
||||||
|
</dd>
|
||||||
|
<dt>Private files</dt>
|
||||||
|
<dd>Files that rightfully belong to your app and should be deleted when the user uninstalls
|
||||||
|
your app. Although these files are technically accessible by the user and other apps because they
|
||||||
|
are on the external storage, they are files that realistically don't provide value to the user
|
||||||
|
outside your app. When the user uninstalls your app, the system deletes
|
||||||
|
all files in your app's external private directory.
|
||||||
|
<p>For example, additional resources downloaded by your app or temporary media files.</p>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<p>If you want to save public files on the external storage, use the
|
||||||
|
{@link android.os.Environment#getExternalStoragePublicDirectory
|
||||||
|
getExternalStoragePublicDirectory()} method to get a {@link java.io.File} representing
|
||||||
|
the appropriate directory on the external storage. The method takes an argument specifying
|
||||||
|
the type of file you want to save so that they can be logically organized with other public
|
||||||
|
files, such as {@link android.os.Environment#DIRECTORY_MUSIC} or {@link
|
||||||
|
android.os.Environment#DIRECTORY_PICTURES}. For example:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public File getAlbumStorageDir(String albumName) {
|
||||||
|
// Get the directory for the user's public pictures directory.
|
||||||
|
File file = new File(Environment.getExternalStoragePublicDirectory(
|
||||||
|
Environment.DIRECTORY_PICTURES), albumName);
|
||||||
|
if (!file.mkdirs()) {
|
||||||
|
Log.e(LOG_TAG, "Directory not created");
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<p>If you want to save files that are private to your app, you can acquire the
|
||||||
|
appropriate directory by calling {@link
|
||||||
|
android.content.Context#getExternalFilesDir getExternalFilesDir()} and passing it a name indicating
|
||||||
|
the type of directory you'd like. Each directory created this way is added to a parent
|
||||||
|
directory that encapsulates all your app's external storage files, which the system deletes when the
|
||||||
|
user uninstalls your app.</p>
|
||||||
|
|
||||||
|
<p>For example, here's a method you can use to create a directory for an individual photo album:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public File getAlbumStorageDir(Context context, String albumName) {
|
||||||
|
// Get the directory for the app's private pictures directory.
|
||||||
|
File file = new File(context.getExternalFilesDir(
|
||||||
|
Environment.DIRECTORY_PICTURES), albumName);
|
||||||
|
if (!file.mkdirs()) {
|
||||||
|
Log.e(LOG_TAG, "Directory not created");
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>If none of the pre-defined sub-directory names suit your files, you can instead call {@link
|
||||||
|
android.content.Context#getExternalFilesDir getExternalFilesDir()} and pass {@code null}. This
|
||||||
|
returns the root directory for your app's private directory on the external storage.</p>
|
||||||
|
|
||||||
|
<p>Remember that {@link android.content.Context#getExternalFilesDir getExternalFilesDir()}
|
||||||
|
creates a directory inside a directory that is deleted when the user uninstalls your app.
|
||||||
|
If the files you're saving should remain available after the user uninstalls your
|
||||||
|
app—such as when your app is a camera and the user will want to keep the photos—you
|
||||||
|
should instead use {@link android.os.Environment#getExternalStoragePublicDirectory
|
||||||
|
getExternalStoragePublicDirectory()}.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Regardless of whether you use {@link
|
||||||
|
android.os.Environment#getExternalStoragePublicDirectory
|
||||||
|
getExternalStoragePublicDirectory()} for files that are shared or
|
||||||
|
{@link android.content.Context#getExternalFilesDir
|
||||||
|
getExternalFilesDir()} for files that are private to your app, it's important that you use
|
||||||
|
directory names provided by API constants like
|
||||||
|
{@link android.os.Environment#DIRECTORY_PICTURES}. These directory names ensure
|
||||||
|
that the files are treated properly by the system. For instance, files saved in {@link
|
||||||
|
android.os.Environment#DIRECTORY_RINGTONES} are categorized by the system media scanner as ringtones
|
||||||
|
instead of music.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="GetFreeSpace">Query Free Space</h2>
|
||||||
|
|
||||||
|
<p>If you know ahead of time how much data you're saving, you can find out
|
||||||
|
whether sufficient space is available without causing an {@link
|
||||||
|
java.io.IOException} by calling {@link java.io.File#getFreeSpace} or {@link
|
||||||
|
java.io.File#getTotalSpace}. These methods provide the current available space and the
|
||||||
|
total space in the storage volume, respectively. This information is also useful to avoid filling
|
||||||
|
the storage volume above a certain threshold.</p>
|
||||||
|
|
||||||
|
<p>However, the system does not guarantee that you can write as many bytes as are
|
||||||
|
indicated by {@link java.io.File#getFreeSpace}. If the number returned is a
|
||||||
|
few MB more than the size of the data you want to save, or if the file system
|
||||||
|
is less than 90% full, then it's probably safe to proceed.
|
||||||
|
Otherwise, you probably shouldn't write to storage.</p>
|
||||||
|
|
||||||
|
<p class="note"><strong>Note:</strong> You aren't required to check the amount of available space
|
||||||
|
before you save your file. You can instead try writing the file right away, then
|
||||||
|
catch an {@link java.io.IOException} if one occurs. You may need to do
|
||||||
|
this if you don't know exactly how much space you need. For example, if you
|
||||||
|
change the file's encoding before you save it by converting a PNG image to
|
||||||
|
JPEG, you won't know the file's size beforehand.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="DeleteFile">Delete a File</h2>
|
||||||
|
|
||||||
|
<p>You should always delete files that you no longer need. The most straightforward way to delete a
|
||||||
|
file is to have the opened file reference call {@link java.io.File#delete} on itself.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
myFile.delete();
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>If the file is saved on internal storage, you can also ask the {@link android.content.Context} to locate and
|
||||||
|
delete a file by calling {@link android.content.Context#deleteFile deleteFile()}:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
myContext.deleteFile(fileName);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
<p><strong>Note:</strong> When the user uninstalls your app, the Android system deletes
|
||||||
|
the following:</p>
|
||||||
|
<ul>
|
||||||
|
<li>All files you saved on internal storage</li>
|
||||||
|
<li>All files you saved on external storage using {@link
|
||||||
|
android.content.Context#getExternalFilesDir getExternalFilesDir()}.</li>
|
||||||
|
</ul>
|
||||||
|
<p>However, you should manually delete all cached files created with
|
||||||
|
{@link android.content.Context#getCacheDir()} on a regular basis and also regularly delete
|
||||||
|
other files you no longer need.</p>
|
||||||
|
</div>
|
||||||
|
|
55
docs/html/training/basics/data-storage/index.jd
Normal file
55
docs/html/training/basics/data-storage/index.jd
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
page.title=Saving Data
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
startpage=true
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>Dependencies and prerequisites</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Android 1.6 (API Level 4) or higher</li>
|
||||||
|
<li>Familiarity with Map key-value collections</li>
|
||||||
|
<li>Familiarity with the Java file I/O API</li>
|
||||||
|
<li>Familiarity with SQL databases</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/data/data-storage.html">Storage Options</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>Most Android apps need to save data, even if only to save information about the app state
|
||||||
|
during {@link android.app.Activity#onPause onPause()} so the user's progress is not lost. Most
|
||||||
|
non-trivial apps also need to save user settings, and some apps must manage large
|
||||||
|
amounts of information in files and databases. This class introduces you to the
|
||||||
|
principal data storage options in Android, including:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Saving key-value pairs of simple data types in a shared preferences
|
||||||
|
file</li>
|
||||||
|
<li>Saving arbitrary files in Android's file system</li>
|
||||||
|
<li>Using databases managed by SQLite</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Lessons</h2>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><b><a href="shared-preferences.html">Saving Data in Shared Preferences</a></b></dt>
|
||||||
|
<dd>Learn to use a shared preferences file for storing small amounts of information in
|
||||||
|
key-value pairs.</dd>
|
||||||
|
|
||||||
|
<dt><b><a href="files.html">Saving Data in Files</a></b></dt>
|
||||||
|
<dd>Learn to save a basic file, such as to store long sequences of data that
|
||||||
|
are generally read in order.</dd>
|
||||||
|
|
||||||
|
<dt><b><a href="databases.html">Saving Data in SQL Databases</a></b></dt>
|
||||||
|
<dd>Learn to use a SQLite database to read and write structured data.</dd>
|
||||||
|
|
||||||
|
</dl>
|
121
docs/html/training/basics/data-storage/shared-preferences.jd
Normal file
121
docs/html/training/basics/data-storage/shared-preferences.jd
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
page.title=Saving Key-Value Sets
|
||||||
|
parent.title=Data Storage
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>This lesson teaches you to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#GetSharedPreferences">Get a Handle to a SharedPreferences</a></li>
|
||||||
|
<li><a href="#WriteSharedPreference">Write to Shared Preferences</a></li>
|
||||||
|
<li><a href="#ReadSharedPreference">Read from Shared Preferences</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/data/data-storage.html#pref">Using Shared Preferences</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>If you have a relatively small collection of key-values that you'd like to save,
|
||||||
|
you should use the {@link android.content.SharedPreferences} APIs.
|
||||||
|
A {@link android.content.SharedPreferences} object points to a file containing
|
||||||
|
key-value pairs and provides simple methods to read and write them. Each
|
||||||
|
{@link android.content.SharedPreferences} file is
|
||||||
|
managed by the framework and can be private or shared.</p>
|
||||||
|
|
||||||
|
<p>This class shows you how to use the {@link android.content.SharedPreferences} APIs to store and
|
||||||
|
retrieve simple values.</p>
|
||||||
|
|
||||||
|
<p class="note"><strong>Note:</strong> The {@link android.content.SharedPreferences} APIs are
|
||||||
|
only for reading and writing key-value pairs and you should not confuse them with the
|
||||||
|
{@link android.preference.Preference} APIs, which help you build a user interface
|
||||||
|
for your app settings (although they use {@link android.content.SharedPreferences} as their
|
||||||
|
implementation to save the app settings). For information about using the {@link
|
||||||
|
android.preference.Preference} APIs, see the <a href="{@docRoot}guide/topics/ui/settings.html"
|
||||||
|
>Settings</a> guide.</p>
|
||||||
|
|
||||||
|
<h2 id="GetSharedPreferences">Get a Handle to a SharedPreferences</h2>
|
||||||
|
|
||||||
|
<p>You can create a new shared preference file or access an existing
|
||||||
|
one by calling one of two methods:</p>
|
||||||
|
<ul>
|
||||||
|
<li>{@link android.content.Context#getSharedPreferences(String,int)
|
||||||
|
getSharedPreferences()} — Use this if you need multiple shared preference files identified
|
||||||
|
by name, which you specify with the first parameter. You can call this from any
|
||||||
|
{@link android.content.Context} in your app.</li>
|
||||||
|
<li>{@link android.app.Activity#getPreferences(int) getPreferences()} — Use this from an
|
||||||
|
{@link android.app.Activity} if you need
|
||||||
|
to use only one shared preference file for the activity. Because this retrieves a default shared
|
||||||
|
preference file that belongs to the activity, you don't need to supply a name.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>For example, the following code is executed inside a {@link android.app.Fragment}.
|
||||||
|
It accesses the shared preferences file that's
|
||||||
|
identified by the resource string {@code R.string.preference_file_key} and opens it using
|
||||||
|
the private mode so the file is accessible by only your app.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
Context context = getActivity();
|
||||||
|
SharedPreferences sharedPref = context.getSharedPreferences(
|
||||||
|
getString(R.string.preference_file_key), Context.MODE_PRIVATE);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>When naming your shared preference files, you should use a name that's uniquely identifiable
|
||||||
|
to your app, such as {@code "com.example.myapp.PREFERENCE_FILE_KEY"}</p>
|
||||||
|
|
||||||
|
<p>Alternatively, if you need just one shared preference file for your activity, you can use the
|
||||||
|
{@link android.app.Activity#getPreferences(int) getPreferences()} method:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p class="caution"><strong>Caution:</strong> If you create a shared preferences file
|
||||||
|
with {@link android.content.Context#MODE_WORLD_READABLE} or {@link
|
||||||
|
android.content.Context#MODE_WORLD_WRITEABLE}, then any other apps that know the file identifier
|
||||||
|
can access your data.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="WriteSharedPreference">Write to Shared Preferences</h2>
|
||||||
|
|
||||||
|
<p>To write to a shared preferences file, create a {@link
|
||||||
|
android.content.SharedPreferences.Editor} by calling {@link
|
||||||
|
android.content.SharedPreferences#edit} on your {@link android.content.SharedPreferences}.</p>
|
||||||
|
|
||||||
|
<p>Pass the keys and values you want to write with methods such as {@link
|
||||||
|
android.content.SharedPreferences.Editor#putInt putInt()} and {@link
|
||||||
|
android.content.SharedPreferences.Editor#putString putString()}. Then call {@link
|
||||||
|
android.content.SharedPreferences.Editor#commit} to save the changes. For example:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = sharedPref.edit();
|
||||||
|
editor.putInt(getString(R.string.saved_high_score), newHighScore);
|
||||||
|
editor.commit();
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="ReadSharedPreference">Read from Shared Preferences</h2>
|
||||||
|
|
||||||
|
<p>To retrieve values from a shared preferences file, call methods such as {@link
|
||||||
|
android.content.SharedPreferences#getInt getInt()} and {@link
|
||||||
|
android.content.SharedPreferences#getString getString()}, providing the key for the value
|
||||||
|
you want, and optionally a default value to return if the key isn't
|
||||||
|
present. For example:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
|
||||||
|
long default = getResources().getInteger(R.string.saved_high_score_default));
|
||||||
|
long highScore = sharedPref.getInt(getString(R.string.saved_high_score), default);
|
||||||
|
</pre>
|
||||||
|
|
@ -103,6 +103,26 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-section">
|
||||||
|
<div class="nav-section-header"><a href="<?cs var:toroot?>training/basics/data-storage/index.html">
|
||||||
|
<span class="en">Saving Data</span>
|
||||||
|
</a></div>
|
||||||
|
<ul>
|
||||||
|
<li><a href="<?cs var:toroot ?>training/basics/data-storage/shared-preferences.html">
|
||||||
|
<span class="en">Saving Key-Value Sets</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="<?cs var:toroot ?>training/basics/data-storage/files.html">
|
||||||
|
<span class="en">Saving Files</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="<?cs var:toroot ?>training/basics/data-storage/databases.html">
|
||||||
|
<span class="en">Saving Data in SQL Databases</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="nav-section">
|
<li class="nav-section">
|
||||||
<div class="nav-section-header"><a href="<?cs var:toroot ?>training/basics/intents/index.html">
|
<div class="nav-section-header"><a href="<?cs var:toroot ?>training/basics/intents/index.html">
|
||||||
<span class="en">Interacting with Other Apps</span>
|
<span class="en">Interacting with Other Apps</span>
|
||||||
|
Reference in New Issue
Block a user