938 lines
46 KiB
Plaintext
938 lines
46 KiB
Plaintext
page.title=Data Backup
|
|
@jd:body
|
|
|
|
|
|
<div id="qv-wrapper">
|
|
<div id="qv">
|
|
|
|
<h2>Quickview</h2>
|
|
<ul>
|
|
<li>Back up the user's data to the cloud in case the user loses it</li>
|
|
<li>If the user upgrades to a new Android-powered device, your app can restore the user's
|
|
data onto the new device</li>
|
|
<li>Easily back up SharedPreferences and private files with BackupAgentHelper</li>
|
|
<li>Requires API Level 8</li>
|
|
</ul>
|
|
|
|
<h2>In this document</h2>
|
|
<ol>
|
|
<li><a href="#Basics">The Basics</a></li>
|
|
<li><a href="#BackupManifest">Declaring the Backup Agent in Your Manifest</a></li>
|
|
<li><a href="#BackupKey">Registering for Android Backup Service</a></li>
|
|
<li><a href="#BackupAgent">Extending BackupAgent</a>
|
|
<ol>
|
|
<li><a href="#RequiredMethods">Required Methods</a></li>
|
|
<li><a href="#PerformingBackup">Performing backup</a></li>
|
|
<li><a href="#PerformingRestore">Performing restore</a></li>
|
|
</ol>
|
|
</li>
|
|
<li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
|
|
<ol>
|
|
<li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
|
|
<li><a href="#Files">Backing up Private Files</a></li>
|
|
</ol>
|
|
</li>
|
|
<li><a href="#RestoreVersion">Checking the Restore Data Version</a></li>
|
|
<li><a href="#RequestingBackup">Requesting Backup</a></li>
|
|
<li><a href="#RequestingRestore">Requesting Restore</a></li>
|
|
<li><a href="#Testing">Testing Your Backup Agent</a></li>
|
|
</ol>
|
|
|
|
<h2>Key classes</h2>
|
|
<ol>
|
|
<li>{@link android.app.backup.BackupManager}</li>
|
|
<li>{@link android.app.backup.BackupAgent}</li>
|
|
<li>{@link android.app.backup.BackupAgentHelper}</li>
|
|
</ol>
|
|
|
|
<h2>See also</h2>
|
|
<ol>
|
|
<li><a href="{@docRoot}guide/developing/tools/bmgr.html">{@code bmgr} tool</a></li>
|
|
</ol>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<p>Android's {@link android.app.backup backup} service allows you to copy your persistent
|
|
application data to remote "cloud" storage, in order to provide a restore point for the
|
|
application data and settings. If a user performs a factory reset or converts to a new
|
|
Android-powered device, the system automatically restores your backup data when the application
|
|
is re-installed. This way, your users don't need to reproduce their previous data or
|
|
application settings. This process is completely transparent to the user and does not affect the
|
|
functionality or user experience in your application.</p>
|
|
|
|
<p>During a backup operation (which your application can request), Android's Backup Manager ({@link
|
|
android.app.backup.BackupManager}) queries your application for backup data, then hands it to
|
|
a backup transport, which then delivers the data to the cloud storage. During a
|
|
restore operation, the Backup Manager retrieves the backup data from the backup transport and
|
|
returns it to your application so your application can restore the data to the device. It's
|
|
possible for your application to request a restore, but that shouldn't be necessary—Android
|
|
automatically performs a restore operation when your application is installed and there exists
|
|
backup data associated with the user. The primary scenario in which backup data is restored is when
|
|
a user resets their device or upgrades to a new device and their previously installed
|
|
applications are re-installed.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> The backup service is <em>not</em> designed for
|
|
synchronizing application data with other clients or saving data that you'd like to access during
|
|
the normal application lifecycle. You cannot read or write backup data on demand and cannot access
|
|
it in any way other than through the APIs provided by the Backup Manager.</p>
|
|
|
|
<p>The backup transport is the client-side component of Android's backup framework, which is
|
|
customizable by
|
|
the device manufacturer and service provider. The backup transport may differ from device to device
|
|
and which backup transport is available on any given device is transparent to your application. The
|
|
Backup Manager APIs isolate your application from the actual backup transport available on a given
|
|
device—your application communicates with the Backup Manager through a fixed set of APIs,
|
|
regardless of the underlying transport.</p>
|
|
|
|
<p>Data backup is <em>not</em> guaranteed to be available on all Android-powered
|
|
devices. However, your application is not adversely affected in the event
|
|
that a device does not provide a backup transport. If you believe that users will benefit from data
|
|
backup in your application, then you can implement it as described in this document, test it, then
|
|
publish your application without any concern about which devices actually perform backup. When your
|
|
application runs on a device that does not provide a backup transport, your application operates
|
|
normally, but will not receive callbacks from the Backup Manager to backup data.</p>
|
|
|
|
<p>Although you cannot know what the current transport is, you are always assured that your
|
|
backup data cannot be read by other applications on the device. Only the Backup Manager and backup
|
|
transport have access to the data you provide during a backup operation.</p>
|
|
|
|
<p class="caution"><strong>Caution:</strong> Because the cloud storage and transport service can
|
|
differ from device to device, Android makes no guarantees about the security of your data while
|
|
using backup. You should always be cautious about using backup to store sensitive data, such as
|
|
usernames and passwords.</p>
|
|
|
|
|
|
<h2 id="Basics">The Basics</h2>
|
|
|
|
<p>To backup your application data, you need to implement a backup agent. Your backup
|
|
agent is called by the Backup Manager to provide the data you want to back up. It is also called
|
|
to restore your backup data when the application is re-installed. The Backup Manager handles all
|
|
your data transactions with the cloud storage (using the backup transport) and your backup agent
|
|
handles all your data transactions on the device.</p>
|
|
|
|
<p>To implement a backup agent, you must:</p>
|
|
|
|
<ol>
|
|
<li>Declare your backup agent in your manifest file with the <a
|
|
href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
|
|
android:backupAgent}</a> attribute.</li>
|
|
<li>Register your application with a backup service. Google offers <a
|
|
href="http://code.google.com/android/backup/index.html">Android Backup Service</a> as a backup
|
|
service for most Android-powered devices, which requires that you register your application in
|
|
order for it to work. Any other backup services available might also require you to register
|
|
in order to store your data on their servers.</li>
|
|
<li>Define a backup agent by either:</p>
|
|
<ol type="a">
|
|
<li><a href="#BackupAgent">Extending BackupAgent</a>
|
|
<p>The {@link android.app.backup.BackupAgent} class provides the central interface with
|
|
which your application communicates with the Backup Manager. If you extend this class
|
|
directly, you must override {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} and {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()} to handle the backup and restore operations for your data.</p>
|
|
<p><em>Or</em></p>
|
|
<li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
|
|
<p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
|
|
wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
|
|
you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
|
|
"helper" objects, which automatically backup and restore certain types of data, so that you do not
|
|
need to implement {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} and {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()}.</p>
|
|
<p>Android currently provides backup helpers that will backup and restore complete files
|
|
from {@link android.content.SharedPreferences} and <a
|
|
href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
|
|
</li>
|
|
</ol>
|
|
</li>
|
|
</ol>
|
|
|
|
|
|
|
|
<h2 id="BackupManifest">Declaring the Backup Agent in Your Manifest</h2>
|
|
|
|
<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
|
|
it in your manifest with the <a
|
|
href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
|
|
android:backupAgent}</a> attribute in the <a
|
|
href="{@docRoot}guide/topics/manifest/application-element.html">{@code
|
|
<application>}</a> tag.</p>
|
|
|
|
<p>For example:</p>
|
|
|
|
<pre>
|
|
<manifest ... >
|
|
...
|
|
<application android:label="MyApplication"
|
|
<b>android:backupAgent="MyBackupAgent"</b>>
|
|
<activity ... >
|
|
...
|
|
</activity>
|
|
</application>
|
|
</manifest>
|
|
</pre>
|
|
|
|
<p>Another attribute you might want to use is <a
|
|
href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
|
|
android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
|
|
want to restore the application data regardless of the current application version compared to the
|
|
version that produced the backup data. (The default value is "{@code false}".) See <a
|
|
href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
|
|
available only on devices running API Level 8 (Android 2.2) or greater, so you should also
|
|
set your <a
|
|
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
|
|
attribute to "8". However, if you implement proper <a
|
|
href="{@docRoot}resources/articles/backward-compatibility.html">backward compatibility</a> in
|
|
your application, you can support this feature for devices running API Level 8 or greater, while
|
|
remaining compatible with older devices.</p>
|
|
|
|
|
|
|
|
|
|
<h2 id="BackupKey">Registering for Android Backup Service</h2>
|
|
|
|
<p>Google provides a backup transport with <a
|
|
href="http://code.google.com/android/backup/index.html">Android Backup Service</a> for most
|
|
Android-powered devices running Android 2.2 or greater.</p>
|
|
|
|
<p>In order for you application to perform backup using Android Backup Service, you must
|
|
register your application with the service to receive a Backup Service Key, then
|
|
declare the Backup Service Key in your Android manifest.</p>
|
|
|
|
<p>To get your Backup Service Key, <a
|
|
href="http://code.google.com/android/backup/signup.html">register for Android Backup Service</a>.
|
|
When you register, you will be provided a Backup Service Key and the appropriate {@code
|
|
<meta-data>} XML code for your Android manifest file, which you must include as a child of the
|
|
{@code <application>} element. For example:</p>
|
|
|
|
<pre>
|
|
<application android:label="MyApplication"
|
|
android:backupAgent="MyBackupAgent">
|
|
...
|
|
<meta-data android:name="com.google.android.backup.api_key"
|
|
android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" />
|
|
</application>
|
|
</pre>
|
|
|
|
<p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and
|
|
the <code>android:value</code> must be the Backup Service Key received from the Android Backup
|
|
Service registration.</p>
|
|
|
|
<p>If you have multiple applications, you must register each one, using the respective package
|
|
name.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is
|
|
not guaranteed to be available
|
|
on all Android-powered devices that support backup. Some devices might support backup
|
|
using a different transport, some devices might not support backup at all, and there is no way for
|
|
your application to know what transport is used on the device. However, if you implement backup for
|
|
your application, you should always include a Backup Service Key for Android Backup Service so
|
|
your application can perform backup when the device uses the Android Backup Service transport. If
|
|
the device does not use Android Backup Service, then the {@code <meta-data>} element with the
|
|
Backup Service Key is ignored.</p>
|
|
|
|
|
|
|
|
|
|
<h2 id="BackupAgent">Extending BackupAgent</h2>
|
|
|
|
<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
|
|
directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
|
|
advantage of the built-in helper classes that automatically backup and restore your files. However,
|
|
you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
|
|
<ul>
|
|
<li>Version your data format. For instance, if you anticipate the need to revise the
|
|
format in which you write your application data, you can build a backup agent to cross-check your
|
|
application version during a restore operation and perform any necessary compatibility work if the
|
|
version on the device is different than that of the backup data. For more information, see <a
|
|
href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
|
|
<li>Instead of backing up an entire file, you can specify the portions of data the should be
|
|
backed up and how each portion is then restored to the device. (This can also help you manage
|
|
different versions, because you read and write your data as unique entities, rather than
|
|
complete files.)</li>
|
|
<li>Back up data in a database. If you have an SQLite database that you want to restore when
|
|
the user re-installs your application, you need to build a custom {@link
|
|
android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
|
|
create your table and insert the data during a restore operation.</li>
|
|
</ul>
|
|
|
|
<p>If you don't need to perform any of the tasks above and want to back up complete files from
|
|
{@link android.content.SharedPreferences} or <a
|
|
href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
|
|
should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
|
|
|
|
|
|
|
|
<h3 id="RequiredMethods">Required Methods</h3>
|
|
|
|
<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
|
|
must implement the following callback methods:</p>
|
|
|
|
<dl>
|
|
<dt>{@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()}</dt>
|
|
<dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a
|
|
backup</a>. In this method, you read your application data from the device and pass the data you
|
|
want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
|
|
backup</a>.</dd>
|
|
|
|
<dt>{@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()}</dt>
|
|
<dd>The Backup Manager calls this method during a restore operation (you can <a
|
|
href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when
|
|
the user re-installs your application). When it calls this method, the Backup Manager delivers your
|
|
backup data, which you then restore to the device, as described below in <a
|
|
href="#PerformingRestore">Performing restore</a>.</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3 id="PerformingBackup">Performing backup</h3>
|
|
|
|
|
|
<p>When it's time to back up your application data, the Backup Manager calls your {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} method. This is where you must provide your application data to the Backup Manager so
|
|
it can be saved to cloud storage.</p>
|
|
|
|
<p>Only the Backup Manager can call your backup agent's {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} method. Each time that your application data changes and you want to perform a backup,
|
|
you must request a backup operation by calling {@link
|
|
android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
|
|
Backup</a> for more information). A backup request does not result in an immediate call to your
|
|
{@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
|
|
backup for all applications that have requested a backup since the last backup was performed.</p>
|
|
|
|
<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
|
|
immediate backup operation from the Backup Manager with the <a
|
|
href="{@docRoot}guide/developing/tools/bmgr.html">{@code bmgr} tool</a>.</p>
|
|
|
|
<p>When the Backup Manager calls your {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} method, it passes three parameters:</p>
|
|
|
|
<dl>
|
|
<dt>{@code oldState}</dt>
|
|
<dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
|
|
state provided by your application. This is not the backup data from cloud storage, but a
|
|
local representation of the data that was backed up the last time {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} was called (as defined by {@code newState}, below, or from {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()}—more about this in the next section). Because {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} does not allow you to read existing backup data in
|
|
the cloud storage, you can use this local representation to determine whether your data has changed
|
|
since the last backup.</dd>
|
|
<dt>{@code data}</dt>
|
|
<dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
|
|
data to the Backup Manager.</dd>
|
|
<dt>{@code newState}</dt>
|
|
<dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
|
|
you must write a representation of the data that you delivered to {@code data} (a representation
|
|
can be as simple as the last-modified timestamp for your file). This object is
|
|
returned as {@code oldState} the next time the Backup Manager calls your {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
|
|
will point to an empty file next time Backup Manager calls {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()}.</dd>
|
|
</dl>
|
|
|
|
<p>Using these parameters, you should implement your {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} method to do the following:</p>
|
|
|
|
<ol>
|
|
<li>Check whether your data has changed since the last backup by comparing {@code oldState} to
|
|
your current data. How you read data in {@code oldState} depends on how you originally wrote it to
|
|
{@code newState} (see step 3). The easiest way to record the state of a file is with its
|
|
last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
|
|
oldState}:
|
|
<pre>
|
|
// Get the oldState input stream
|
|
FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
|
|
DataInputStream in = new DataInputStream(instream);
|
|
|
|
try {
|
|
// Get the last modified timestamp from the state file and data file
|
|
long stateModified = in.readLong();
|
|
long fileModified = mDataFile.lastModified();
|
|
|
|
if (stateModified != fileModified) {
|
|
// The file has been modified, so do a backup
|
|
// Or the time on the device changed, so be safe and do a backup
|
|
} else {
|
|
// Don't back up because the file hasn't changed
|
|
return;
|
|
}
|
|
} catch (IOException e) {
|
|
// Unable to read state file... be safe and do a backup
|
|
}
|
|
</pre>
|
|
<p>If nothing has changed and you don't need to back up, skip to step 3.</p>
|
|
</li>
|
|
<li>If your data has changed, compared to {@code oldState}, write the current data to
|
|
{@code data} to back it up to the cloud storage.
|
|
<p>You must write each chunk of data as an "entity" in the {@link
|
|
android.app.backup.BackupDataOutput}. An entity is a flattened binary data
|
|
record that is identified by a unique key string. Thus, the data set that you back up is
|
|
conceptually a set of key-value pairs.</p>
|
|
<p>To add an entity to your backup data set, you must:</p>
|
|
<ol>
|
|
<li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
|
|
writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
|
|
size.</li>
|
|
<li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
|
|
writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
|
|
from the buffer (which should match the size passed to {@link
|
|
android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
|
|
</ol>
|
|
<p>For example, the following code flattens some data into a byte stream and writes it into a
|
|
single entity:</p>
|
|
<pre>
|
|
// Create buffer stream and data output stream for our data
|
|
ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
|
|
DataOutputStream outWriter = new DataOutputStream(bufStream);
|
|
// Write structured data
|
|
outWriter.writeUTF(mPlayerName);
|
|
outWriter.writeInt(mPlayerScore);
|
|
// Send the data to the Backup Manager via the BackupDataOutput
|
|
byte[] buffer = bufStream.toByteArray();
|
|
int len = buffer.length;
|
|
data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
|
|
data.writeEntityData(buffer, len);
|
|
</pre>
|
|
<p>Perform this for each piece of data that you want to back up. How you divide your data into
|
|
entities is up to you (and you might use just one entity).</p>
|
|
</li>
|
|
<li>Whether or not you perform a backup (in step 2), write a representation of the current data to
|
|
the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
|
|
locally as a representation of the data that is currently backed up. It passes this back to you as
|
|
{@code oldState} the next time it calls {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
|
|
do not write the current data state to this file, then
|
|
{@code oldState} will be empty during the next callback.
|
|
<p>The following example saves a representation of the current data into {@code newState} using
|
|
the file's last-modified timestamp:</p>
|
|
<pre>
|
|
FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
|
|
DataOutputStream out = new DataOutputStream(outstream);
|
|
|
|
long modified = mDataFile.lastModified();
|
|
out.writeLong(modified);
|
|
</pre>
|
|
</li>
|
|
</ol>
|
|
|
|
<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
|
|
that you use synchronized statements while accessing the file so that your backup agent does not
|
|
read the file while an Activity in your application is also writing the file.</p>
|
|
|
|
|
|
|
|
|
|
<h3 id="PerformingRestore">Performing restore</h3>
|
|
|
|
<p>When it's time to restore your application data, the Backup Manager calls your backup
|
|
agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
|
|
you can restore it onto the device.</p>
|
|
|
|
<p>Only the Backup Manager can call {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()}, which happens automatically when the system installs your application and
|
|
finds existing backup data. However, you can request a restore operation for
|
|
your application by calling {@link
|
|
android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
|
|
href="#RequestingRestore">Requesting restore</a> for more information).</p>
|
|
|
|
<p class="note"><strong>Note:</strong> While developing your application, you can also request a
|
|
restore operation with the <a href="{@docRoot}guide/developing/tools/bmgr.html">{@code bmgr}
|
|
tool</a>.</p>
|
|
|
|
<p>When the Backup Manager calls your {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()} method, it passes three parameters:</p>
|
|
|
|
<dl>
|
|
<dt>{@code data}</dt>
|
|
<dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
|
|
data.</dd>
|
|
<dt>{@code appVersionCode}</dt>
|
|
<dd>An integer representing the value of your application's <a
|
|
href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
|
|
manifest attribute, as it was when this data was backed up. You can use this to cross-check the
|
|
current application version and determine if the data format is compatible. For more
|
|
information about using this to handle different versions of restore data, see the section
|
|
below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
|
|
<dt>{@code newState}</dt>
|
|
<dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
|
|
you must write the final backup state that was provided with {@code data}. This object is
|
|
returned as {@code oldState} the next time {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} is called. Recall that you must also write the same {@code newState} object in the
|
|
{@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} callback—also doing it here ensures that the {@code oldState} object given to
|
|
{@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} is valid even the first time {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} is called after the device is restored.</dd>
|
|
</dl>
|
|
|
|
<p>In your implementation of {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
|
|
{@code data} to iterate
|
|
through all entities in the data set. For each entity found, do the following:</p>
|
|
|
|
<ol>
|
|
<li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
|
|
<li>Compare the entity key to a list of known key values that you should have declared as static
|
|
final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
|
|
your known key strings, enter into a statement to extract the entity data and save it to the device:
|
|
<ol>
|
|
<li>Get the entity data size with {@link
|
|
android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
|
|
<li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
|
|
readEntityData()} and pass it the byte array, which is where the data will go, and specify the
|
|
start offset and the size to read.</li>
|
|
<li>Your byte array is now full and you can read the data and write it to the device
|
|
however you like.</li>
|
|
</ol>
|
|
</li>
|
|
<li>After you read and write your data back to the device, write the state of your data to the
|
|
{@code newState} parameter the same as you do during {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()}.
|
|
</ol>
|
|
|
|
<p>For example, here's how you can restore the data backed up by the example in the previous
|
|
section:</p>
|
|
|
|
<pre>
|
|
@Override
|
|
public void onRestore(BackupDataInput data, int appVersionCode,
|
|
ParcelFileDescriptor newState) throws IOException {
|
|
// There should be only one entity, but the safest
|
|
// way to consume it is using a while loop
|
|
while (data.readNextHeader()) {
|
|
String key = data.getKey();
|
|
int dataSize = data.getDataSize();
|
|
|
|
// If the key is ours (for saving top score). Note this key was used when
|
|
// we wrote the backup entity header
|
|
if (TOPSCORE_BACKUP_KEY.equals(key)) {
|
|
// Create an input stream for the BackupDataInput
|
|
byte[] dataBuf = new byte[dataSize];
|
|
data.readEntityData(dataBuf, 0, dataSize);
|
|
ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
|
|
DataInputStream in = new DataInputStream(baStream);
|
|
|
|
// Read the player name and score from the backup data
|
|
mPlayerName = in.readUTF();
|
|
mPlayerScore = in.readInt();
|
|
|
|
// Record the score on the device (to a file or something)
|
|
recordScore(mPlayerName, mPlayerScore);
|
|
} else {
|
|
// We don't know this entity key. Skip it. (Shouldn't happen.)
|
|
data.skipEntityData();
|
|
}
|
|
}
|
|
|
|
// Finally, write to the state blob (newState) that describes the restored data
|
|
FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
|
|
DataOutputStream out = new DataOutputStream(outstream);
|
|
out.writeUTF(mPlayerName);
|
|
out.writeInt(mPlayerScore);
|
|
}
|
|
</pre>
|
|
|
|
<p>In this example, the {@code appVersionCode} parameter passed to {@link
|
|
android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
|
|
it if you've chosen to perform backup when the user's version of the application has actually moved
|
|
backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
|
|
the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
|
|
|
|
<div class="special">
|
|
<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
|
|
href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
|
|
ExampleAgent}</a> class in the <a
|
|
href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
|
|
application.</p>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
|
|
|
|
<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
|
|
to back up complete files (from either {@link android.content.SharedPreferences} or <a
|
|
href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
|
|
Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
|
|
code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
|
|
{@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} and {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()}.</p>
|
|
|
|
<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
|
|
use one or more backup helpers. A backup helper is a specialized
|
|
component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
|
|
restore operations for a particular type of data. The Android framework currently provides two
|
|
different helpers:</p>
|
|
<ul>
|
|
<li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
|
|
android.content.SharedPreferences} files.</li>
|
|
<li>{@link android.app.backup.FileBackupHelper} to backup files from <a
|
|
href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
|
|
</ul>
|
|
|
|
<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
|
|
one helper is needed for each data type. That is, if you have multiple {@link
|
|
android.content.SharedPreferences} files, then you need only one {@link
|
|
android.app.backup.SharedPreferencesBackupHelper}.</p>
|
|
|
|
<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
|
|
the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
|
|
<ol>
|
|
<li>Instantiate in instance of the desired helper class. In the class constructor, you must
|
|
specify the appropriate file(s) you want to backup.</li>
|
|
<li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
|
|
to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
|
|
</ol>
|
|
|
|
<p>The following sections describe how to create a backup agent using each of the available
|
|
helpers.</p>
|
|
|
|
|
|
|
|
<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
|
|
|
|
<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
|
|
include the name of one or more {@link android.content.SharedPreferences} files.</p>
|
|
|
|
<p>For example, to back up a {@link android.content.SharedPreferences} file named
|
|
"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
|
|
like this:</p>
|
|
|
|
<pre>
|
|
public class MyPrefsBackupAgent extends BackupAgentHelper {
|
|
// The name of the SharedPreferences file
|
|
static final String PREFS = "user_preferences";
|
|
|
|
// A key to uniquely identify the set of backup data
|
|
static final String PREFS_BACKUP_KEY = "prefs";
|
|
|
|
// Allocate a helper and add it to the backup agent
|
|
@Override
|
|
public void onCreate() {
|
|
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
|
|
addHelper(PREFS_BACKUP_KEY, helper);
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>That's it! That's your entire backup agent. The {@link
|
|
android.app.backup.SharedPreferencesBackupHelper} includes all the code
|
|
needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
|
|
|
|
<p>When the Backup Manager calls {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} and {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
|
|
backup and restore for your specified files.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> {@link android.content.SharedPreferences} are threadsafe, so
|
|
you can safely read and write the shared preferences file from your backup agent and
|
|
other activities.</p>
|
|
|
|
|
|
|
|
<h3 id="Files">Backing up other files</h3>
|
|
|
|
<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
|
|
one or more files that are saved to your application's <a
|
|
href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
|
|
(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
|
|
location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
|
|
files).</p>
|
|
|
|
<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
|
|
android.app.backup.BackupAgentHelper} looks like this:</p>
|
|
|
|
<pre>
|
|
public class MyFileBackupAgent extends BackupAgentHelper {
|
|
// The name of the SharedPreferences file
|
|
static final String TOP_SCORES = "scores";
|
|
static final String PLAYER_STATS = "stats";
|
|
|
|
// A key to uniquely identify the set of backup data
|
|
static final String FILES_BACKUP_KEY = "myfiles";
|
|
|
|
// Allocate a helper and add it to the backup agent
|
|
void onCreate() {
|
|
FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS);
|
|
addHelper(FILES_BACKUP_KEY, helper);
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
|
|
restore files that are saved to your application's <a
|
|
href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
|
|
|
|
<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
|
|
ensure that your backup agent does not read or write your files at the same time as your activities,
|
|
you must use synchronized statements each time you perform a read or write. For example,
|
|
in any Activity where you read and write the file, you need an object to use as the intrinsic
|
|
lock for the synchronized statements:</p>
|
|
|
|
<div class="sidebox-wrapper">
|
|
<div class="sidebox">
|
|
<p><strong>Interesting Fact:</strong></p>
|
|
<p>A zero-length array is lighter-weight than a normal Object, so it's great for an
|
|
intrinsic lock.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<pre>
|
|
// Object for intrinsic lock
|
|
static final Object[] sDataLock = new Object[0];
|
|
</pre>
|
|
|
|
<p>Then create a synchronized statement with this lock each time you read or write the files. For
|
|
example, here's a synchronized statement for writing the latest score in a game to a file:</p>
|
|
|
|
<pre>
|
|
try {
|
|
synchronized (MyActivity.sDataLock) {
|
|
File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
|
|
RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
|
|
raFile.writeInt(score);
|
|
}
|
|
} catch (IOException e) {
|
|
Log.e(TAG, "Unable to write to file");
|
|
}
|
|
</pre>
|
|
|
|
<p>You should synchronize your read statements with the same lock.</p>
|
|
|
|
<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} and {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()} to synchronize the backup and restore operations with the same
|
|
intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
|
|
methods:</p>
|
|
|
|
<pre>
|
|
@Override
|
|
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
|
ParcelFileDescriptor newState) throws IOException {
|
|
// Hold the lock while the FileBackupHelper performs backup
|
|
synchronized (MyActivity.sDataLock) {
|
|
super.onBackup(oldState, data, newState);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRestore(BackupDataInput data, int appVersionCode,
|
|
ParcelFileDescriptor newState) throws IOException {
|
|
// Hold the lock while the FileBackupHelper restores the file
|
|
synchronized (MyActivity.sDataLock) {
|
|
super.onRestore(data, appVersionCode, newState);
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
|
|
{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} and {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
|
|
onRestore()} to synchronize read and write operations.</p>
|
|
|
|
<div class="special">
|
|
<p>For an example implementation of {@link
|
|
android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
|
|
{@code FileHelperExampleAgent} class in the <a
|
|
href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
|
|
application.</p>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 id="RestoreVersion">Checking the Restore Data Version</h2>
|
|
|
|
<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
|
|
of your application, as defined by your manifest file's <a
|
|
href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
|
|
attribute. Before the Backup Manager calls your backup agent to restore your data, it
|
|
looks at the <a
|
|
href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
|
|
android:versionCode}</a> of the installed application and compares it to the value
|
|
recorded in the restore data set. If the version recorded in the restore data set is
|
|
<em>newer</em> than the application version on the device, then the user has downgraded their
|
|
application. In this case, the Backup Manager will abort the restore operation for your application
|
|
and not call your {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
|
|
method, because the restore set is considered meaningless to an older version.</p>
|
|
|
|
<p>You can override this behavior with the <a
|
|
href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
|
|
android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
|
|
false}" to indicate whether you want to restore the application regardless of the restore set
|
|
version. The default value is "{@code false}". If you define this to be "{@code true}" then the
|
|
Backup Manager will ignore the <a
|
|
href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
|
|
and call your {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
|
|
method in all cases. In doing so, you can manually check for the version difference in your {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
|
|
method and take any steps necessary to make the data compatible if the versions conflict.</p>
|
|
|
|
<p>To help you handle different versions during a restore operation, the {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
|
|
method passes you the version code included with the restore data set as the {@code appVersionCode}
|
|
parameter. You can then query the current application's version code with the {@link
|
|
android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
|
|
|
|
<pre>
|
|
PackageInfo info;
|
|
try {
|
|
String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
|
|
info = {@link android.content.ContextWrapper#getPackageManager
|
|
getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
|
|
getPackageInfo}(name,0);
|
|
} catch (NameNotFoundException nnfe) {
|
|
info = null;
|
|
}
|
|
|
|
int version;
|
|
if (info != null) {
|
|
version = info.versionCode;
|
|
}
|
|
</pre>
|
|
|
|
<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
|
|
to the {@code appVersionCode} passed into {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
|
|
</p>
|
|
|
|
<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
|
|
<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
|
|
android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
|
|
application that supports backup does not properly account for variations in your data format during
|
|
{@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
|
|
then the data on the device could be saved in a format incompatible with the version currently
|
|
installed on the device.</p>
|
|
|
|
|
|
|
|
<h2 id="RequestingBackup">Requesting Backup</h2>
|
|
|
|
<p>You can request a backup operation at any time by calling {@link
|
|
android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
|
|
like to backup your data using your backup agent. The Backup Manager then calls your backup
|
|
agent's {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()} method at an opportune time in the future. Typically, you should
|
|
request a backup each time your data changes (such as when the user changes an application
|
|
preference that you'd like to back up). If you call {@link
|
|
android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
|
|
Manager requests a backup from your agent, your agent still receives just one call to {@link
|
|
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
|
|
onBackup()}.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> While developing your application, you can request a
|
|
backup and initiate an immediate backup operation with the <a
|
|
href="{@docRoot}guide/developing/tools/bmgr.html">{@code bmgr}
|
|
tool</a>.</p>
|
|
|
|
|
|
<h2 id="RequestingRestore">Requesting Restore</h2>
|
|
|
|
<p>During the normal life of your application, you shouldn't need to request a restore operation.
|
|
They system automatically checks for backup data and performs a restore when your application is
|
|
installed. However, you can manually request a restore operation by calling {@link
|
|
android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
|
|
which case, the Backup Manager calls your {@link
|
|
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
|
|
implementation, passing the data from the current set of backup data.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> While developing your application, you can request a
|
|
restore operation with the <a href="{@docRoot}guide/developing/tools/bmgr.html">{@code bmgr}
|
|
tool</a>.</p>
|
|
|
|
|
|
<h2 id="Testing">Testing Your Backup Agent</h2>
|
|
|
|
<p>Once you've implemented your backup agent, you can test the backup and restore functionality
|
|
with the following procedure, using <a
|
|
href="{@docRoot}guide/developing/tools/bmgr.html">{@code bmgr}</a>.</p>
|
|
|
|
<ol>
|
|
<li>Install your application on a suitable Android system image
|
|
<ul>
|
|
<li>If using the emulator, create and use an AVD with Android 2.2 (API Level 8).</li>
|
|
<li>If using a device, the device must be running Android 2.2 or greater and have Android
|
|
Market built in.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Ensure that backup is enabled
|
|
<ul>
|
|
<li>If using the emulator, you can enable backup with the following command from your SDK
|
|
{@code tools/} path:
|
|
<pre class="no-pretty-print">adb shell bmgr enable true</pre>
|
|
</li>
|
|
<li>If using a device, open the system <b>Settings</b>, select <b>Privacy</b>, then enable
|
|
<b>Back up my data</b> and <b>Automatic restore</b>.
|
|
</ul>
|
|
</li>
|
|
<li>Open your application and initialize some data
|
|
<p>If you've properly implemented backup in your application, then it should request a
|
|
backup each time the data changes. For example, each time the user changes some data, your app
|
|
should call {@link android.app.backup.BackupManager#dataChanged()}, which adds a backup request to
|
|
the Backup Manager queue. For testing purposes, you can also make a request with the following
|
|
{@code bmgr} command:</p>
|
|
<pre class="no-pretty-print">adb shell bmgr backup <em>your.package.name</em></pre>
|
|
</li>
|
|
<li>Initiate a backup operation:
|
|
<pre class="no-pretty-print">adb shell bmgr run</pre>
|
|
<p>This forces the Backup Manager to perform all backup requests that are in its
|
|
queue.</p>
|
|
<li>Uninstall your application:
|
|
<pre class="no-pretty-print">adb uninstall <em>your.package.name</em></pre>
|
|
</li>
|
|
<li>Re-install your application.</li>
|
|
</ol>
|
|
|
|
<p>If your backup agent is successful, all the data you initialized in step 4 is restored.</p>
|
|
|
|
|