am 773740ed: Initial commit of backup API section of cloudsync class.

* commit '773740ed79075e6daffaea0c62857348ab54d93e':
  Initial commit of backup API section of cloudsync class.
This commit is contained in:
Alexander Lucas
2012-04-18 20:19:56 -07:00
committed by Android Git Automerger
4 changed files with 683 additions and 5 deletions

View File

@ -123,6 +123,23 @@ class="new">&nbsp;new!</span></span>
</ul>
</li>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>training/cloudsync/index.html">
<span class="en">Syncing to the Cloud<span class="new">&nbsp;new!</span></span>
</a></div>
<ul>
<li><a href="<?cs var:toroot ?>training/cloudsync/aesync.html">
<span class="en">Syncing with App Engine</span>
</a>
</li>
<li><a href="<?cs var:toroot ?>training/cloudsync/backupapi.html">
<span class="en">Using the Backup API</span>
</a>
</li>
</ul>
</li>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>training/search/index.html">
<span class="en">Adding Search Functionality<span class="new">&nbsp;new!</span></span>
@ -369,11 +386,11 @@ class="new">&nbsp;new!</span></span>
</li>
<li><a href="<?cs var:toroot ?>training/displaying-bitmaps/display-bitmap.html">
<span class="en">Displaying Bitmaps in Your UI</span>
</a>
</li>
</ul>
<ul>
</li>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>training/accessibility/index.html">
<span class="en">Implementing Accessibility<span class="new">&nbsp;new!</span></span>
@ -394,6 +411,8 @@ class="new">&nbsp;new!</span></span>
</li>
<li>
<span class="heading">
<span class="en">Technical Resources</span>

View File

@ -0,0 +1,432 @@
page.title=Syncing with App Engine
parent.title=Syncing to the Cloud
parent.link=index.html
trainingnavtop=true
next.title=Using the Backup API
next.link=backupapi.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<!-- table of contents -->
<h2>This lesson teaches you how to</h2>
<ol>
<li><a href="#prepare">Prepare Your Environment</a></li>
<li><a href="#project">Create Your Project</a></li>
<li><a href="#data">Create the Data Layer</a></li>
<li><a href="#persistence">Create the Persistence Layer</a></li>
<li><a href="#androidapp">Query and Update from the Android App</a></li>
<li><a href="#serverc2dm">Configure the C2DM Server-Side</a></li>
<li><a href="#clientc2dm">Configure the C2DM Client-Side</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a
href="http://developers.google.com/appengine/">App Engine</a></li>
<li><a href="http://code.google.com/android/c2dm/">Android Cloud to Device
Messaging Framework</a></li>
</ul>
<h2>Try it out</h2>
<p>This lesson uses the Cloud Tasks sample code, originally shown at the
<a href="http://www.youtube.com/watch?v=M7SxNNC429U">Android + AppEngine: A Developer's Dream Combination</a>
talk at Google I/O. You can use the sample application as a source of reusable code for your own
application, or simply as a reference for how the Android and cloud pieces of the overall
application fit together. You can also build the sample application and see how it runs
on your own device or emulator.</p>
<p>
<a href="http://code.google.com/p/cloud-tasks-io/" class="button">Cloud Tasks
App</a>
</p>
</div>
</div>
<p>Writing an app that syncs to the cloud can be a challenge. There are many little
details to get right, like server-side auth, client-side auth, a shared data
model, and an API. One way to make this much easier is to use the Google Plugin
for Eclipse, which handles a lot of the plumbing for you when building Android
and App Engine applications that talk to each other. This lesson walks you through building such a project.</p>
<p>Following this lesson shows you how to:</p>
<ul>
<li>Build Android and Appengine apps that can communicate with each other</li>
<li>Take advantage of Cloud to Device Messaging (C2DM) so your Android app doesn't have to poll for updates</li>
</ul>
<p>This lesson focuses on local development, and does not cover distribution
(i.e, pushing your App Engine app live, or publishing your Android App to
market), as those topics are covered extensively elsewhere.</p>
<h2 id="prepare">Prepare Your Environment</h2>
<p>If you want to follow along with the code example in this lesson, you must do
the following to prepare your development environment:</p>
<ul>
<li>Install the <a href="http://code.google.com/eclipse/">Google Plugin for
Eclipse.</a></li>
<li>Install the <a
href="http://code.google.com/webtoolkit/download.html">GWT SDK</a> and the <a
href="http://code.google.com/appengine/">Java App Engine SDK</a>. The <a
href="http://code.google.com/eclipse/docs/getting_started.html">Quick Start
Guide</a> shows you how to install these components.</li>
<li>Sign up for <a href="http://code.google.com/android/c2dm/signup.html">C2DM
access</a>. We strongly recommend <a
href="https://accounts.google.com/SignUp">creating a new Google account</a> specifically for
connecting to C2DM. The server component in this lesson uses this <em>role
account</em> repeatedly to authenticate with Google servers.
</li>
</ul>
<h2 id="project">Create Your Projects</h2>
<p>After installing the Google Plugin for Eclipse, notice that a new kind of Android project
exists when you create a new Eclipse project: The <strong>App Engine Connected
Android Project</strong> (under the <strong>Google</strong> project category).
A wizard guides you through creating this project,
during the course of which you are prompted to enter the account credentials for the role
account you created.</p>
<p class="note"><strong>Note:</strong> Remember to enter the credentials for
your <i>role account</i> (the one you created to access C2DM services), not an
account you'd log into as a user, or as an admin.</p>
<p>Once you're done, you'll see two projects waiting for you in your
workspace&mdash;An Android application and an App Engine application. Hooray!
These two applications are already fully functional&mdash; the wizard has
created a sample application which lets you authenticate to the App Engine
application from your Android device using AccountManager (no need to type in
your credentials), and an App Engine app that can send messages to any logged-in
device using C2DM. In order to spin up your application and take it for a test
drive, do the following:</p>
<p>To spin up the Android application, make sure you have an AVD with a platform
version of <em>at least</em> Android 2.2 (API Level 8). Right click on the Android project in
Eclipse, and go to <strong>Debug As &gt; Local App Engine Connected Android
Application</strong>. This launches the emulator in such a way that it can
test C2DM functionality (which typically works through Google Play). It'll
also launch a local instance of App Engine containing your awesome
application.</p>
<h2 id="data">Create the Data Layer</h2>
<p>At this point you have a fully functional sample application running. Now
it's time to start changing the code to create your own application.</p>
<p>First, create the data model that defines the data shared between
the App Engine and Android applications. To start, open up the source folder of
your App Engine project, and navigate down to the <strong>(yourApp)-AppEngine
&gt; src &gt; (yourapp) &gt; server</strong> package. Create a new class in there containing some data you want to
store server-side. The code ends up looking something like this:</p>
<pre>
package com.cloudtasks.server;
import javax.persistence.*;
&#64;Entity
public class Task {
private String emailAddress;
private String name;
private String userId;
private String note;
&#64;Id
&#64;GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public Task() {
}
public String getEmailAddress() {
return this.emailAddress;
}
public Long getId() {
return this.id;
}
...
}
</pre>
<p>Note the use of annotations: <code>Entity</code>, <code>Id</code> and
<code>GeneratedValue</code> are all part of the <a
href="http://www.oracle.com/technetwork/articles/javaee/jpa-137156.html">Java
Persistence API</a>. Essentially, the <code>Entity</code> annotation goes
above the class declaration, and indicates that this class represents an entity
in your data layer. The <code>Id</code> and <code>GeneratedValue</code>
annotations, respectively, indicate the field used as a lookup key for this
class, and how that id is generated (in this case,
<code>GenerationType.IDENTITY</code> indicates that the is generated by
the database). You can find more on this topic in the App Engine documentation,
on the page <a
href="http://code.google.com/appengine/docs/java/datastore/jpa/overview.html">Using
JPA with App Engine</a>.</p>
<p>Once you've written all the classes that represent entities in your data
layer, you need a way for the Android and App Engine applications to communicate
about this data. This communication is enabled by creating a Remote Procedure
Call (RPC) service.
Typically, this involves a lot of monotonous code. Fortunately, there's an easy way! Right
click on the server project in your App Engine source folder, and in the context
menu, navigate to <strong>New &gt; Other</strong> and then, in the resulting
screen, select <strong>Google &gt; RPC Service.</strong> A wizard appears, pre-populated
with all the Entities you created in the previous step,
which it found by seeking out the <code>&#64;Entity</code> annotation in the
source files you added. Pretty neat, right? Click <strong>Finish</strong>, and the wizard
creates a Service class with stub methods for the Create, Retrieve, Update and
Delete (CRUD) operations of all your entities.</p>
<h2 id="persistence">Create the Persistence Layer</h2>
<p>The persistence layer is where your application data is stored
long-term, so any information you want to keep for your users needs to go here.
You have several options for writing your persistence layer, depending on
what kind of data you want to store. A few of the options hosted by Google
(though you don't have to use these services) include <a
href="http://code.google.com/apis/storage/">Google Storage for Developers</a>
and App Engine's built-in <a
href="http://code.google.com/appengine/docs/java/gettingstarted/usingdatastore.html">Datastore</a>.
The sample code for this lesson uses DataStore code.</p>
<p>Create a class in your <code>com.cloudtasks.server</code> package to handle
persistence layer input and output. In order to access the data store, use the <a
href="http://db.apache.org/jdo/api20/apidocs/javax/jdo/PersistenceManager.html">PersistenceManager</a>
class. You can generate an instance of this class using the PMF class in the
<code>com.google.android.c2dm.server.PMF</code> package, and then use that to
perform basic CRUD operations on your data store, like this:</p>
<pre>
/**
* Remove this object from the data store.
*/
public void delete(Long id) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Task item = pm.getObjectById(Task.class, id);
pm.deletePersistent(item);
} finally {
pm.close();
}
}
</pre>
<p>You can also use <a
href="http://code.google.com/appengine/docs/python/datastore/queryclass.html">Query</a>
objects to retrieve data from your Datastore. Here's an example of a method
that searches out an object by its ID.</p>
<pre>
public Task find(Long id) {
if (id == null) {
return null;
}
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Query query = pm.newQuery("select from " + Task.class.getName()
+ " where id==" + id.toString() + " && emailAddress=='" + getUserEmail() + "'");
List<Task> list = (List<Task>) query.execute();
return list.size() == 0 ? null : list.get(0);
} catch (RuntimeException e) {
System.out.println(e);
throw e;
} finally {
pm.close();
}
}
</pre>
<p>For a good example of a class that encapsulates the persistence layer for
you, check out the <a
href="http://code.google.com/p/cloud-tasks-io/source/browse/trunk/CloudTasks-AppEngine/src/com/cloudtasks/server/DataStore.java">DataStore</a>
class in the Cloud Tasks app.</p>
<h2 id="androidapp">Query and Update from the Android App</h2>
<p>In order to keep in sync with the App Engine application, your Android application
needs to know how to do two things: Pull data from the cloud, and send data up
to the cloud. Much of the plumbing for this is generated by the
plugin, but you need to wire it up to your Android user interface yourself.</p>
<p>Pop open the source code for the main Activity in your project and look for
<code>&lt;YourProjectName&gt; Activity.java</code>, then for the method
<code>setHelloWorldScreenContent()</code>. Obviously you're not building a
HelloWorld app, so delete this method entirely and replace it
with something relevant. However, the boilerplate code has some very important
characteristics. For one, the code that communicates with the cloud is wrapped
in an {@link android.os.AsyncTask} and therefore <em>not</em> hitting the
network on the UI thread. Also, it gives an easy template for how to access
the cloud in your own code, using the <a
href="http://code.google.com/webtoolkit/doc/latest/DevGuideRequestFactory.html">RequestFactory</a>
class generated that was auto-generated for you by the Eclipse plugin (called
MyRequestFactory in the example below), and various {@code Request} types.</p>
<p>For instance, if your server-side data model included an object called {@code
Task} when you generated an RPC layer it automatically created a
{@code TaskRequest} class for you, as well as a {@code TaskProxy} representing the individual
task. In code, requesting a list of all these tasks from the server looks
like this:</p>
<pre>
public void fetchTasks (Long id) {
// Request is wrapped in an AsyncTask to avoid making a network request
// on the UI thread.
new AsyncTask<Long, Void, List<TaskProxy>>() {
&#64;Override
protected List<TaskProxy> doInBackground(Long... arguments) {
final List<TaskProxy> list = new ArrayList<TaskProxy>();
MyRequestFactory factory = Util.getRequestFactory(mContext,
MyRequestFactory.class);
TaskRequest taskRequest = factory.taskNinjaRequest();
if (arguments.length == 0 || arguments[0] == -1) {
factory.taskRequest().queryTasks().fire(new Receiver<List<TaskProxy>>() {
&#64;Override
public void onSuccess(List<TaskProxy> arg0) {
list.addAll(arg0);
}
});
} else {
newTask = true;
factory.taskRequest().readTask(arguments[0]).fire(new Receiver<TaskProxy>() {
&#64;Override
public void onSuccess(TaskProxy arg0) {
list.add(arg0);
}
});
}
return list;
}
&#64;Override
protected void onPostExecute(List<TaskProxy> result) {
TaskNinjaActivity.this.dump(result);
}
}.execute(id);
}
...
public void dump (List<TaskProxy> tasks) {
for (TaskProxy task : tasks) {
Log.i("Task output", task.getName() + "\n" + task.getNote());
}
}
</pre>
<p>This {@link android.os.AsyncTask} returns a list of
<code>TaskProxy</code> objects, and sends it to the debug {@code dump()} method
upon completion. Note that if the argument list is empty, or the first argument
is a -1, all tasks are retrieved from the server. Otherwise, only the ones with
IDs in the supplied list are returned. All the fields you added to the task
entity when building out the App Engine application are available via get/set
methods in the <code>TaskProxy</code> class.</p>
<p>In order to create new tasks and send them to the cloud, create a request
object and use it to create a proxy object. Then populate the proxy object and
call its update method. Once again, this should be done in an
<code>AsyncTask</code> to avoid doing networking on the UI thread. The end
result looks something like this.</p>
<pre>
new AsyncTask<Void, Void, Void>() {
&#64;Override
protected Void doInBackground(Void... arg0) {
MyRequestFactory factory = (MyRequestFactory)
Util.getRequestFactory(TasksActivity.this,
MyRequestFactory.class);
TaskRequest request = factory.taskRequest();
// Create your local proxy object, populate it
TaskProxy task = request.create(TaskProxy.class);
task.setName(taskName);
task.setNote(taskDetails);
task.setDueDate(dueDate);
// To the cloud!
request.updateTask(task).fire();
return null;
}
}.execute();
</pre>
<h2 id="serverc2dm">Configure the C2DM Server-Side</h2>
<p>In order to set up C2DM messages to be sent to your Android device, go back
into your App Engine codebase, and open up the service class that was created
when you generated your RPC layer. If the name of your project is Foo,
this class is called FooService. Add a line to each of the methods for
adding, deleting, or updating data so that a C2DM message is sent to the
user's device. Here's an example of an update task:
</p>
<pre>
public static Task updateTask(Task task) {
task.setEmailAddress(DataStore.getUserEmail());
task = db.update(task);
DataStore.sendC2DMUpdate(TaskChange.UPDATE + TaskChange.SEPARATOR + task.getId());
return task;
}
// Helper method. Given a String, send it to the current user's device via C2DM.
public static void sendC2DMUpdate(String message) {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
ServletContext context = RequestFactoryServlet.getThreadLocalRequest().getSession().getServletContext();
SendMessage.sendMessage(context, user.getEmail(), message);
}
</pre>
<p>In the following example, a helper class, {@code TaskChange}, has been created with a few
constants. Creating such a helper class makes managing the communication
between App Engine and Android apps much easier. Just create it in the shared
folder, define a few constants (flags for what kind of message you're sending
and a seperator is typically enough), and you're done. By way of example,
the above code works off of a {@code TaskChange} class defined as this:</p>
<pre>
public class TaskChange {
public static String UPDATE = "Update";
public static String DELETE = "Delete";
public static String SEPARATOR = ":";
}
</pre>
<h2 id="clientc2dm">Configure the C2DM Client-Side</h2>
<p>In order to define the Android applications behavior when a C2DM is recieved,
open up the <code>C2DMReceiver</code> class, and browse to the
<code>onMessage()</code> method. Tweak this method to update based on the content
of the message.</p>
<pre>
//In your C2DMReceiver class
public void notifyListener(Intent intent) {
if (listener != null) {
Bundle extras = intent.getExtras();
if (extras != null) {
String message = (String) extras.get("message");
String[] messages = message.split(Pattern.quote(TaskChange.SEPARATOR));
listener.onTaskUpdated(messages[0], Long.parseLong(messages[1]));
}
}
}
</pre>
<pre>
// Elsewhere in your code, wherever it makes sense to perform local updates
public void onTasksUpdated(String messageType, Long id) {
if (messageType.equals(TaskChange.DELETE)) {
// Delete this task from your local data store
...
} else {
// Call that monstrous Asynctask defined earlier.
fetchTasks(id);
}
}
</pre>
<p>
Once you have C2DM set up to trigger local updates, you're all done.
Congratulations, you have a cloud-connected Android application!</p>

View File

@ -0,0 +1,193 @@
page.title=Using the Backup API
parent.title=Syncing to the Cloud
parent.link=index.html
trainingnavtop=true
previous.title=Syncing with App Engine
previous.link=aesync.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#register">Register for the Android Backup Service</a></li>
<li><a href="#manifest">Configure Your Manifest</a></li>
<li><a href="#agent">Write Your Backup Agent</a></li>
<li><a href="#backup">Request a Backup</a></li>
<li><a href="#restore">Restore from a Backup</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a
href="http://developer.android.com/guide/topics/data/backup.html">Data
Backup</a></li>
</ul>
</div>
</div>
<p>When a user purchases a new device or resets their existing one, they might
expect that when Google Play restores your app back to their device during the
initial setup, the previous data associated with the app restores as well. By
default, that doesn't happen and all the user's accomplishments or settings in
your app are lost.</p>
<p>For situations where the volume of data is relatively light (less than a
megabyte), like the user's preferences, notes, game high scores or other
stats, the Backup API provides a lightweight solution. This lesson walks you
through integrating the Backup API into your application, and restoring data to
new devices using the Backup API.</p>
<h2 id="register">Register for the Android Backup Service</h2>
<p>This lesson requires the use of the <a
href="http://code.google.com/android/backup/index.html">Android Backup
Service</a>, which requires registration. Go ahead and <a
href="http://code.google.com/android/backup/signup.html">register here</a>. Once
that's done, the service pre-populates an XML tag for insertion in your Android
Manifest, which looks like this:</p>
<pre>
&lt;meta-data android:name="com.google.android.backup.api_key"
android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /&gt;
</pre>
<p>Note that each backup key works with a specific package name. If you have
different applications, register separate keys for each one.</p>
<h2 id="manifest">Configure Your Manifest</h2>
<p>Use of the Android Backup Service requires two additions to your application
manifest. First, declare the name of the class that acts as your backup agent,
then add the snippet above as a child element of the Application tag. Assuming
your backup agent is going to be called {@code TheBackupAgent}, here's an example of
what the manifest looks like with this tag included:</p>
<pre>
&lt;application android:label="MyApp"
android:backupAgent="TheBackupAgent"&gt;
...
&lt;meta-data android:name="com.google.android.backup.api_key"
android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /&gt;
...
&lt;/application&gt;
</pre>
<h2 id="agent">Write Your Backup Agent</h2>
<p>The easiest way to create your backup agent is by extending the wrapper class
{@link android.app.backup.BackupAgentHelper}. Creating this helper class is
actually a very simple process. Just create a class with the same name as you
used in the manifest in the previous step (in this example, {@code
TheBackupAgent}),
and extend {@code BackupAgentHelper}. Then override the {@link
android.app.backup.BackupAgent#onCreate()}.</p>
<p>Inside the {@link android.app.backup.BackupAgent#onCreate()} method, create a {@link
android.app.backup.BackupHelper}. These helpers are
specialized classes for backing up certain kinds of data. The Android framework
currently includes two such helpers: {@link
android.app.backup.FileBackupHelper} and {@link
android.app.backup.SharedPreferencesBackupHelper}. After you create the helper
and point it at the data you want to back up, just add it to the
BackupAgentHelper using the {@link android.app.backup.BackupAgentHelper#addHelper(String, BackupHelper) addHelper()}
method, adding a key which is used to
retrieve the data later. In most cases the entire
implementation is perhaps 10 lines of code.</p>
<p>Here's an example that backs up a high scores file.</p>
<pre>
import android.app.backup.BackupAgentHelper;
import android.app.backup.FileBackupHelper;
public class TheBackupAgent extends BackupAgentHelper {
// The name of the SharedPreferences file
static final String HIGH_SCORES_FILENAME = "scores";
// 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
&#64;Override
void onCreate() {
FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME);
addHelper(FILES_BACKUP_KEY, helper);
}
}
</pre>
<p>For added flexibility, {@link android.app.backup.FileBackupHelper}'s
constructor can take a variable number of filenames. You could just as easily
have backed up both a high scores file and a game progress file just by adding
an extra parameter, like this:</p>
<pre>
&#64;Override
void onCreate() {
FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME, PROGRESS_FILENAME);
addHelper(FILES_BACKUP_KEY, helper);
}
</pre>
<p>Backing up preferences is similarly easy. Create a {@link
android.app.backup.SharedPreferencesBackupHelper} the same way you did a {@link
android.app.backup.FileBackupHelper}. In this case, instead of adding filenames
to the constructor, add the names of the shared preference groups being used by
your application. Here's an example of how your backup agent helper might look if
high scores are implemented as preferences instead of a flat file:</p>
<pre>
import android.app.backup.BackupAgentHelper;
import android.app.backup.SharedPreferencesBackupHelper;
public class TheBackupAgent extends BackupAgentHelper {
// The names of the SharedPreferences groups that the application maintains. These
// are the same strings that are passed to getSharedPreferences(String, int).
static final String PREFS_DISPLAY = "displayprefs";
static final String PREFS_SCORES = "highscores";
// An arbitrary string used within the BackupAgentHelper implementation to
// identify the SharedPreferencesBackupHelper's data.
static final String MY_PREFS_BACKUP_KEY = "myprefs";
// Simply allocate a helper and install it
void onCreate() {
SharedPreferencesBackupHelper helper =
new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
addHelper(MY_PREFS_BACKUP_KEY, helper);
}
}
</pre>
<p>You can add as many backup helper instances to your backup agent helper as you
like, but remember that you only need one of each type. One {@link
android.app.backup.FileBackupHelper} handles all the files that you need to back up, and one
{@link android.app.backup.SharedPreferencesBackupHelper} handles all the shared
preferencegroups you need backed up.
</p>
<h2 id="backup">Request a Backup</h2>
<p>In order to request a backup, just create an instance of the {@link
android.app.backup.BackupManager}, and call it's {@link
android.app.backup.BackupManager#dataChanged()} method.</p>
<pre>
import android.app.backup.BackupManager;
...
public void requestBackup() {
BackupManager bm = new BackupManager(this);
bm.dataChanged();
}
</pre>
<p>This call notifies the backup manager that there is data ready to be backed
up to the cloud. At some point in the future, the backup manager then calls
your backup agent's {@link
android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput,
ParcelFileDescriptor) onBackup()} method. You can make
the call whenever your data has changed, without having to worry about causing
excessive network activity. If you request a backup twice before a backup
occurs, the backup only occurs once.</p>
<h2 id="restore">Restore from a Backup</h2>
<p>Typically you shouldn't ever have to manually request a restore, as it
happens automatically when your application is installed on a device. However,
if it <em>is</em> necessary to trigger a manual restore, just call the
{@link android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} method.</p>

View File

@ -0,0 +1,34 @@
page.title=Syncing to the Cloud
trainingnavtop=true
startpage=true
next.title=Syncing with App Engine
next.link=aesync.html
@jd:body
<p>By providing powerful APIs for internet connectivity, the Android framework
helps you build rich cloud-enabled apps that sync their data to a remote web
service, making sure all your devices always stay in sync, and your valuable
data is always backed up to the cloud.</p>
<p>This class covers different strategies for cloud enabled applications. It
covers syncing data with the cloud using your own back-end web application, and
backing up data using the cloud so that users can restore their data when
installing your application on a new device.
</p>
<h2>Lessons</h2>
<dl>
<dt><strong><a href="aesync.html">Syncing with App Engine.</a></strong></dt>
<dd>Learn how to create a paired App Engine app and Android app which share a
data model, authenticates using the AccountManager, and communicate with each
other via REST and C2DM.</dd>
<dt><strong><a href="backupapi.html">Using the Backup
API</a></strong></dt>
<dd>Learn how to integrate the Backup API into your Android Application, so
that user data such as preferences, notes, and high scores update seamlessly
across all of a user's devices</dd>
</dl>