diff options
47 files changed, 3845 insertions, 2397 deletions
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml index 8ddb98239038..8cb2ee7b20ad 100644 --- a/docs/html/_redirects.yaml +++ b/docs/html/_redirects.yaml @@ -430,7 +430,13 @@ redirects: - from: /training/cloudsync/aesync.html to: /google/gcm/index.html - from: /training/cloudsync/index.html - to: /training/backup/index.html + to: /guide/topics/data/backup.html +- from: /training/backup/index.html + to: /guide/topics/data/backup.html +- from: /training/backup/autosyncapi.html + to: /guide/topics/data/autobackup.html +- from: /training/backup/backupapi.html + to: /guide/topics/data/keyvaluebackup.html - from: /training/basics/location/... to: /training/location/... - from: /training/monetization/index.html @@ -796,7 +802,7 @@ redirects: - from: /preview/features/app-linking.html to: /training/app-links/index.html - from: /preview/backup/index.html - to: /training/backup/autosyncapi.html + to: /guide/topics/data/backup/autobackup.html - from: /preview/features/power-mgmt.html to: /training/monitoring-device-state/doze-standby.html - from: /preview/dev-community @@ -842,6 +848,10 @@ redirects: to: /topic/performance/power/network/gather-data.html - from: /training/performance/battery/network/index.html to: /topic/performance/power/network/index.html +- from: /training/articles/memory.html + to: /topic/performance/memory.html +- from: /topic/performance/optimizing-view-hierarchies.html + to: /topic/performance/rendering/optimizing-view-hierarchies.html # Redirects for the new [dac]/topic/libraries/ area @@ -1242,6 +1252,44 @@ redirects: to: /studio/write/lint.html?utm_source=android-studio - from: /r/studio-ui/gradle-console.html to: /studio/run/index.html?utm_source=android-studio#gradle-console +- from: /r/studio-ui/app-indexing-test.html + to: /studio/write/app-link-indexing.html#appindexingtest?utm_source=android-studio +- from: /r/studio-ui/vcs.html + to: /studio/intro/index.html#version_control_basics?utm_source=android-studio +- from: /r/studio-ui/create-new-module.html + to: /studio/projects/index.html#ApplicationModules?utm_source=android-studio +- from: /r/studio-ui/build-variants.html + to: /studio/run/index.html#changing-variant?utm_source=android-studio +- from: /r/studio-ui/generate-signed-apk.html + to: /studio/publish/app-signing.html#release-mode?utm_source=android-studio +- from: /r/studio-ui/import-project-vcs.html + to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio +- from: /r/studio-ui/apk-analyzer.html + to: /studio/build/apk-analyzer.html?utm_source=android-studio +- from: /r/studio-ui/breakpoints.html + to: /studio/debug/index.html#breakPointsView?utm_source=android-studio +- from: /r/studio-ui/attach-debugger-to-process.html + to: /studio/debug/index.html?utm_source=android-studio +- from: /r/studio-ui/import-sample.html + to: /samples/index.html?utm_source=android-studio +- from: /r/studio-ui/import-module.html + to: /studio/projects/add-app-module.html#ImportAModule?utm_source=android-studio +- from: /r/studio-ui/import-project.html + to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio +- from: /r/studio-ui/create-project.html + to: /studio/projects/create-project.html?utm_source=android-studio +- from: /r/studio-ui/new-activity.html + to: /studio/projects/template.html?utm_source=android-studio +- from: /r/studio-ui/new-resource-file.html + to: /studio/write/add-resources.html?utm_source=android-studio +- from: /r/studio-ui/new-resource-dir.html + to: /studio/write/add-resources.html#add_a_resource_directory?utm_source=android-studio +- from: /r/studio-ui/configure-component.html + to: /studio/write/add-resources.html?utm_source=android-studio +- from: /r/studio-ui/ninepatch.html + to: /studio/write/draw9patch.html?utm_source=android-studio +- from: /r/studio-ui/firebase-assistant.html + to: /studio/write/firebase.html?utm_source=android-studio # Redirects from (removed) N Preview documentation - from: /preview/features/afw.html diff --git a/docs/html/guide/_book.yaml b/docs/html/guide/_book.yaml index 13c948cc297c..f09fe771bd1a 100644 --- a/docs/html/guide/_book.yaml +++ b/docs/html/guide/_book.yaml @@ -396,6 +396,13 @@ toc: path: /guide/topics/data/data-storage.html - title: Data Backup path: /guide/topics/data/backup.html + section: + - title: Auto Backup + path: /guide/topics/data/autobackup.html + - title: Key/Value Backup + path: /guide/topics/data/keyvaluebackup.html + - title: Testing Backup and Restore + path: /guide/topics/data/testingbackup.html - title: App Install Location path: /guide/topics/data/install-location.html diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 9257a76e93f2..8fe3f201fc2e 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -545,9 +545,16 @@ <li><a href="<?cs var:toroot ?>guide/topics/data/data-storage.html"> <span class="en">Storage Options</span> </a></li> - <li><a href="<?cs var:toroot ?>guide/topics/data/backup.html"> + <li class="nav-section"> + <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/topics/data/backup.html"> <span class="en">Data Backup</span> - </a></li> + </a></div> + <ul> + <li><a href="<?cs var:toroot ?>guide/topics/data/autobackup.html">Auto Backup</a></li> + <li><a href="<?cs var:toroot ?>guide/topics/data/keyvaluebackup.html">Key/Value Backup</a></li> + <li><a href="<?cs var:toroot ?>guide/topics/data/testingbackup.html">Testing Backup and Restore</a></li> + </ul> + </li> <li><a href="<?cs var:toroot ?>guide/topics/data/install-location.html"> <span class="en">App Install Location</span> </a></li> diff --git a/docs/html/guide/topics/data/autobackup.jd b/docs/html/guide/topics/data/autobackup.jd new file mode 100644 index 000000000000..3be09d712884 --- /dev/null +++ b/docs/html/guide/topics/data/autobackup.jd @@ -0,0 +1,257 @@ +page.title=Auto Backup for Apps +page.tags=backup, marshmallow, androidm +page.keywords=backup, autobackup +page.image=images/cards/card-auto-backup_2x.png + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>In this document</h2> + <ol> + <li><a href="#Files">Files that are backed up</a></li> + <li><a href="#BackupLocation">Backup location</a></li> + <li><a href="#BackupSchedule">Backup schedule</a></li> + <li><a href="#RestoreSchedule">Restore schedule</a></li> + <li><a href="#EnablingAutoBackup">Enabling and disabling Auto Backup</a></li> + <li><a href="#IncludingFiles">Including and excluding files</a><ul> + <li><a href="#XMLSyntax">XML config syntax</a></li> + </ul></li> + <li><a href="#ImplementingBackupAgent">Implementing BackupAgent</a></li> + </ol> + + <h2>Key classes</h2> + <ol> + <li>{@link android.app.backup.BackupAgent}</li> + <li><a href="{@docRoot}reference/android/R.attr.html">R.attr</a></li> + </ol> + +</div> +</div> + +Since Android 6.0 (API 23), Android has offered the <em>Auto Backup for Apps</em> feature as +a way for developers to quickly add backup functionality to their apps. Auto +Backup preserves app data by uploading it to the user’s Google Drive account. +The amount of data is limited to 25MB per user of your app and there is no +charge for storing backup data. + +<h2 id="Files">Files that are backed up</h2> +<p>By default, Auto Backup includes files in most of the directories that are +assigned to your app by the system: +<ul> + <li>Shared preferences files. + <li>Files in the directory returned by {@link android.content.Context#getFilesDir()}. + <li>Files in the directory returned by {@link android.content.Context#getDatabasePath(String)}, + which also includes files created with the + {@link android.database.sqlite.SQLiteOpenHelper} class. + <li>Files in directories created with {@link android.content.Context#getDir(String,int)}. + <li>Files on external storage in the directory returned by + {@link android.content.Context#getExternalFilesDir(String)}.</li></ul> + +<p>Auto Backup excludes files in directories returned by + {@link android.content.Context#getCacheDir()}, + {@link android.content.Context#getCodeCacheDir()}, or + {@link android.content.Context#getNoBackupFilesDir()}. The files saved + in these locations are only needed temporarily, or are intentionally + excluded from backup operations. + +<p>You can configure your app to include and exclude particular files. +For more information, see the <a href="#IncludingFiles">Include and exclude files</a> +section. + +<h2 id="BackupLocation">Backup location</h2> +<p>Backup data is stored in a private folder in the user's Google Drive account, +limited to 25MB per app. The saved data does not count towards the user's +personal Google Drive quota. Only the most recent backup is stored. When a +backup is made, the previous backup (if one exists) is deleted. + +<p>Users can see a list of apps that have been backed up in the Google Drive app under +<strong>Settings -> Auto Backup for apps -> Manage backup</strong>. The +backup data cannot be read by the user or other applications on the device. + +<p>Backups from each device-setup-lifetime are stored in separate datasets +as shown in the following examples: +<ul> + <li>If the user owns two devices, then a backup dataset exists for each device. + <li>If the user factory resets a device and then sets up the device with the + same account, the backup is stored in a new dataset. Obsolete datasets are + automatically deleted after a period of inactivity.</li></ul> + +<p class="caution"><strong>Caution:</strong> Once the amount of data reaches +25MB, the app is banned from sending data to the +cloud, even if the amount of data later falls under the 25MB threshold. The ban +affects only the offending device (not other devices that the user owns) and +lasts for the entire device-setup-lifetime. For example, if the user removes and +reinstalls the application, the ban is still in effect. The ban is lifted when +the user performs factory reset on the device. + +<h2 id="BackupSchedule">Backup schedule</h2> +<p>Backups occur automatically when all of the following conditions are met: +<ul> + <li>The user has enabled backup on the device in <strong>Settings</strong> > + <strong>Backup & Reset</strong>. + <li>At least 24 hours have elapsed since the last backup. + <li>The device is idle and charging. + <li>The device is connected to a Wi-Fi network. If the device is never connected + to a wifi network, then Auto Backup never occurs.</li></ul> + +<p>In practice, these conditions occur roughly every night. To conserve network +bandwidth, upload takes place only if app data has changed. + +<p>During Auto Backup, the system shuts down the app to make sure it is no longer +writing to the file system. By default, the backup system ignores apps that are +running in the foreground because users would notice their apps being shut down. +You can override the default behavior by setting the +<a href="{@docRoot}reference/android/R.attr.html#backupInForeground">backupInForeground</a> +attribute to true. + +<p>To simplify testing, Android includes tools that let you manually initiate +a backup of your app. For more information, see +<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>. + +<h2 id="RestoreSchedule">Restore schedule</h2> +<p>Data is restored whenever the app is installed, either from the Play store, +during device setup (when the system installs previously installed apps), or +from running adb install. The restore operation occurs after the APK is +installed, but before the app is available to be launched by the user. + +<p>During the initial device setup wizard, the user is shown a list of available backup +datasets and is asked which one to restore the data from. Whichever backup +dataset is selected becomes the ancestral dataset for the device. The device can +restore from either its own backups or the ancestral dataset. The device +prioritize its own backup if backups from both sources are available. If the +user didn't go through the device setup wizard, then the device can restore only from +its own backups. + +<p>To simplify testing, Android includes tools that let you manually initiate +a restore of your app. For more information, see +<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>. + +<h2 id="EnablingAutoBackup">Enabling and disabling backup</h2> +<p>Apps that target Android 6.0 (API level 23) or higher automatically participate +in Auto Backup. This is because the +<a href="{@docRoot}reference/android/R.attr.html#allowBackup">android:allowBackup</a> +attribute, which enables/disables backup, defaults to <code>true</code> if omitted. +To avoid confusion, we recommend you explicitly set the attribute in the <code><application></code> +element of your <code>AndroidManifest.xml</code>. For example: + +<pre class="prettyprint"><application ... + android:allowBackup="true"> +</app></pre> + +<p>To disable Auto Backup, add either of the following attributes to the +application element in your manifest file: + +<ul> + <li>set <code>android:allowBackup</code> to <code>false</code>. This completely disables data + backup. You may want to disable backups when your app can recreate its state + through some other mechanism or when your app deals with sensitive + information that should not be backed up.</li> + <li>set <code>android:allowBackup</code> to <code>true</code> and + <code>android:fullBackupOnly</code> to <code>false</code>. With these settings, + your app always participates in Key/Value Backup, even when running on devices that + support Auto Backup.</li></ul> + +<h2 id="IncludingFiles">Including and excluding files</h2> +<p>By default, the system backs up almost all app data. For more information, +see <a href="#Files">Files that are backed up</a>. This section shows you how to +define custom XML rules to control what gets backed up. + +<ol> + <li>In <code>AndroidManifest.xml</code>, add the <a href="{@docRoot}reference/android/R.attr.html#fullBackupContent">android:fullBackupContent</a> attribute to the + <code><application></code> element. This attribute points to an XML file that contains backup + rules. For example: + <pre class="prettyprint"><application ... + android:fullBackupContent="@xml/my_backup_rules"> + </app></pre></li> + <li>Create an XML file called <code>my_backup_rules.xml</code> in the <code>res/xml/</code> directory. Inside the file, add rules with the <code><include></code> and <code><exclude></code> elements. The following sample backs up all shared preferences except <code>device.xml</code>: + <pre><?xml version="1.0" encoding="utf-8"?> +<full-backup-content> + <include domain="sharedpref" path="."/> + <exclude domain="sharedpref" path="device.xml"/> +</full-backup-content></pre></li> + +<h3 id="XMLSyntax">XML Config Syntax</h3> +<p>The XML syntax for the configuration file is shown below: + +<pre class="prettyprint"><full-backup-content> + <include domain=["file" | "database" | "sharedpref" | "external" | "root"] + path="string" /> + <exclude domain=["file" | "database" | "sharedpref" | "external" | "root"] + path="string" /> +</full-backup-content></pre> + +<p>Inside the <code><full-backup-content></code> tag, you can define <code><include></code> and <code><exclude></code> +elements: + +<ul> + <li><code><include></code> - Specifies a file or folder to backup. By default, Auto Backup +includes almost all app files. If you specify an <include> element, the system +no longer includes any files by default and backs up <em>only the files +specified</em>. To include multiple files, use multiple <include> elements. + <p>note: Files in directories returned by <code>getCacheDir()</code>, <code>getCodeCacheDir()</code>, or +<code>getNoBackupFilesDir()</code> are always excluded even if you try to include them.</li> + + <li><code><exclude></code> - Specifies a file or folder to exclude during backup. Here are +some files that are typically excluded from backup: <ul> + <li>Files that have device specific identifiers, either issued by a server or +generated on the device. For example, <a href="https://developers.google.com/cloud-messaging/android/start">Google Cloud Messaging (GCM)</a> needs to +generate a registration token every time a user installs your app on a new +device. If the old registration token is restored, the app may behave +unexpectedly. + <li>Account credentials or other sensitive information. Consider asking the +user to reauthenticate the first time they launch a restored app rather than +allowing for storage of such information in the backup. + <li>Files related to app debugging, such as <a href="{@docRoot}studio/run/index.html#instant-run">instant run files</a>. To exclude instant run files, add the rule <code><exclude +domain="file" path="instant-run"/></code> + <li>Large files that cause the app to exceed the 25MB backup quota.</li> </ul> + </li> </ul> + +<p class="note"><strong>Note:</strong> If your configuration file specifies both elements, then the +backup contains everything captured by the <code><include></code> elements minus the +resources named in the <code><exclude></code> elements. In other words, +<code><exclude></code> takes precedence. + +<p>Each element must include the following two attributes: +<ul> + <li><code>domain</code> - specifies the location of resource. Valid values for this attribute +include the following: <ul> + <li><code>root</code> - the directory on the filesystem where all private files belonging to +this app are stored. + <li><code>file</code> - directories returned by {@link android.content.Context#getFilesDir()}. + <li><code>database</code> - directories returned by {@link android.content.Context#getDatabasePath(String) getDatabasePath()}. +Databases created with {@link android.database.sqlite.SQLiteOpenHelper} +are stored here. + <li><code>sharedpref</code> - the directory where {@link android.content.SharedPreferences} +are stored. + <li><code>external</code> the directory returned by {@link android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} + <p>Note: You cannot backup files outside of these locations.</li></ul> + <li><code>path</code>: Specifies a file or folder to include in or exclude from backup. Note +that: <ul> + <li>This attribute does not support wildcard or regex syntax. + <li>You can use <code>.</code> to reference the current directory, however, you cannot +reference the parent directory <code>..</code> for security reasons. + <li>If you specify a directory, then the rule applies to all files in the +directory and recursive sub-directories.</li></ul></li></ul> + +<h2 id="ImplementingBackupAgent">Implementing BackupAgent</h2> +<p>Apps that implement Auto Backup do not need to implement {@link android.app.backup.BackupAgent}. However, you can optionally implement a custom {@link android.app.backup.BackupAgent}. Typically, there are two reasons for doing this: +<ul> + <li>You want to receive notification of backup events such as, +{@link android.app.backup.BackupAgent#onRestoreFinished()} or {@link android.app.backup.BackupAgent#onQuotaExceeded(long,long)}. These callback methods are executed +even if the app is not running. +<li>You can't easily express the set of files you want to backup with XML rules. +In these very rare cases, you can implement a BackupAgent that overrides {@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput)} to +store what you want. To retain the system's default implementation, call the +corresponding method on the superclass with <code>super.onFullBackup()</code>.</li></ul> + +<p class="note"><strong>Note:</strong> Your <code>BackupAgent</code> must +implement the abstract methods +{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) onBackup()} +and {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}. +Those methods are used for Key/Value Backup. So if +you are not using Key/Value Backup, implement those methods and leave them blank. + +<p>For more information, see +<a href="{@docRoot}guide/topics/data/keyvaluebackup.html#BackupAgent">Extending +BackupAgent</a>.
\ No newline at end of file diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd index 619c79021870..a688c6e9889b 100644 --- a/docs/html/guide/topics/data/backup.jd +++ b/docs/html/guide/topics/data/backup.jd @@ -1,930 +1,34 @@ -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}tools/help/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".</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 your 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}tools/help/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}tools/help/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> +page.title=Backing up App Data to the Cloud +page.tags=cloud,sync,backup -<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 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 - @Override - public 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> - -<pre> -// Object for intrinsic lock -static final Object sDataLock = new Object(); -</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}tools/help/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}tools/help/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}tools/help/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 Google -Play 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>Backup & reset</b>, then enable - <b>Back up my data</b> and <b>Automatic restore</b>.</li> - </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> +startpage=true +@jd:body +<p>Users often invest significant time and effort creating data and setting +preferences within apps. Preserving that data for users if they replace a broken +device or upgrade to a new one is an important part of ensuring a great user +experience. This section covers techniques for backing up data to the cloud so +that users can restore their data. + +<p>Android provides two ways for apps to backup their data to the cloud: +<a href="{@docRoot}guide/topics/data/autobackup.html">Auto Backup for Apps</a> and +<a href="{@docRoot}guide/topics/data/keyvaluebackup.html">Key/Value Backup</a>. +Auto Backup, which is available starting API 23, preserves app data by uploading +it to the user’s Google Drive account. The Key/Value Backup feature (formerly +known as the Backup API and the Android Backup Service) preserves app data by +uploading it to the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>. + +<p>Generally, we recommend Auto Backup because it requires no work to implement. +Apps that target Android 6.0 (API level 23) or higher are automatically enabled +for Auto Backup. The Auto Backup feature does have some limitations in terms of +what data it can backup and it's availability on Android 6.0 and higher devices. +Consider using the Key/Value Backup feature if you have more specific needs for +backing up your app data. For more information, see <a href="{@docRoot}guide/topics/data/keyvaluebackup.html#Comparison">Comparison of Key/Value and Auto Backup</a></p> + +<p class="note"><strong>Note:</strong> These data backup features are not designed for synchronizing app 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. For synchronizing app data, see +<a href="{@docRoot}training/sync-adapters/index.html">Transferring +Data Using Sync Adapters</a> or <a href="https://developers.google.com/drive/android/">Google Drive Android +API</a>.
\ No newline at end of file diff --git a/docs/html/guide/topics/data/images/backup-framework.png b/docs/html/guide/topics/data/images/backup-framework.png Binary files differnew file mode 100644 index 000000000000..2ba2e612c9bd --- /dev/null +++ b/docs/html/guide/topics/data/images/backup-framework.png diff --git a/docs/html/guide/topics/data/index.jd b/docs/html/guide/topics/data/index.jd index 3872825f1619..2365f18aaeb8 100644 --- a/docs/html/guide/topics/data/index.jd +++ b/docs/html/guide/topics/data/index.jd @@ -5,21 +5,3 @@ page.landing.image= @jd:body -<div class="landing-docs"> - - - <div class="col-12"> - <h3>Training</h3> - - <a href="{@docRoot}training/backup/index.html"> - <h4>Backing up App Data to the Cloud</h4> - <p> - This class covers techniques for backing up data to the cloud so that - users can restore their data when recovering from a data loss (such as a - factory reset) or installing your application on a new device. - </p> - </a> - - </div> - -</div> diff --git a/docs/html/guide/topics/data/keyvaluebackup.jd b/docs/html/guide/topics/data/keyvaluebackup.jd new file mode 100644 index 000000000000..c7c5e2fd0ce1 --- /dev/null +++ b/docs/html/guide/topics/data/keyvaluebackup.jd @@ -0,0 +1,884 @@ +page.title=Key/Value Backup +page.tags=backup, marshmallow, androidm +page.keywords=backup, kvbackup + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>In this document</h2> + <ol> + <li><a href="#Comparison">Comparison to Auto Backup</a></li> + <li><a href="#ImplementingBackup">Implementing Key/Value Backup</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="#Migrating">Migrating to Auto Backup</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> + +</div> +</div> + + +<p>Since Android 2.2 (API 8), Android has offered the <em>Key/Value Backup</em> +feature as a way for developers to backup app data to the cloud. The Key/Value +Backup feature (formerly known as the Backup API and the Android Backup Service) +preserves app data by uploading it to +<a href="{@docRoot}google/backup/index.html">Android Backup Service</a>. +The amount of data is limited to 5MB per user of your app and there is +no charge for storing backup data. + +<p class="note"><strong>Note:</strong> If your app implements Key/Value Backup +and targets API 23 or higher, you should set +<a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a>. +This attribute indicates whether or not to use Auto Backup on devices where it is available. + +<h2 id="Comparison">Comparison to Auto Backup</h2> +<p>Like Auto Backup, Key/Value Backups are restored automatically whenever the app +is installed. The following table describes some of the key differences between Key/Value Backup and Auto Backup: + +<table> + <tr> + <th>Key/Value Backup</th> + <th>Auto Backup</th> + </tr> + <tr> + <td>Available in API 8, Android 2.2</td> + <td>Available in API 23, Android 6.0</td> + </tr> + <tr> + <td>Apps must implement a {@link android.app.backup.BackupAgent}. The backup agent defines what data to backup and how to +restore data.</td> + <td>By default, Auto Backup includes almost all of the app's files. You can +use XML to include and exclude files. Under the hood, Auto Backup relies on a +backup agent that is built into the framework.</td> + </tr> + <tr> + <td>Apps must issue a request when there is data +that is ready to be backed up. Requests +from multiple apps are batched and executed every few hours.</td> + <td>Backups happen automatically roughly once a day.</td> + </tr> + <tr> + <td>Backup data can be transmitted via wifi or cellular data.</td> + <td>Backup data is tranmitted only via wifi. If the device is never connected to a +wifi network, then Auto Backup never occurs.</td> + </tr> + <tr> + <td>Apps are not shut down during backup.</td> + <td>The system shuts down the app during backup.</td> + </tr> + <tr> + <td>Backup data is stored in <a href="{@docRoot}google/backup/index.html">Android Backup Service</a> limited to 5MB per app.</td> + <td>Backup data is stored in the user's Google Drive limited to 25MB per app.</td> + </tr> + <tr> + <td>Related API methods are not filed based:<ul> + <li>{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} + <li>{@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()}</ul></td> + <td>Related API methods are filed based:<ul> +<li>{@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput) onFullBackup()} +<li>{@link android.app.backup.BackupAgent#onRestoreFile(ParcelFileDescriptor,long,File,int,long,long) onRestoreFile()}</ul></td> + </tr> +</table> + +<h2 id="ImplementingBackup">Implementing Key/Value Backup</h2> +<p>To backup your application data, you need to implement a backup agent. Your backup +agent is called by the Backup Manager both during backup and restore.</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 href="{@docRoot}google/backup/index.html">Android + Backup Service</a></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".</p> + + + + +<h2 id="BackupKey">Registering for Android Backup Service</h2> + +<p>Google provides a backup transport with <a +href="{@docRoot}google/backup/index.html">Android Backup Service</a> for most +Android-powered devices running Android 2.2 or greater.</p> + +<p>In order for your 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="{@docRoot}google/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}tools/help/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}tools/help/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> The methods of {@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 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 + @Override + public 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> + +<pre> +// Object for intrinsic lock +static final Object sDataLock = new Object(); +</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}tools/help/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}tools/help/bmgr.html">{@code bmgr} +tool</a>.</p> + + +<h2 id="Migrating">Migrating to Auto Backup</h2> +<p>You can transition your app to full-data backups by setting <a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a> to <code>true</code> in the <code><application></code> element in the manifest file. When +running on a device with Android 5.1 (API level 22) or lower, your app ignores +this value in the manifest, and continues performing Key/Value Backups. When +running on a device with Android 6.0 (API level 23) or higher, your app performs +Auto Backup instead of Key/Value Backup.
\ No newline at end of file diff --git a/docs/html/guide/topics/data/testingbackup.jd b/docs/html/guide/topics/data/testingbackup.jd new file mode 100644 index 000000000000..6ff5837e2411 --- /dev/null +++ b/docs/html/guide/topics/data/testingbackup.jd @@ -0,0 +1,181 @@ +page.title=Testing Backup and Restore +page.tags=backup, marshmallow, androidm +page.keywords=backup, restore, testing + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>In this document</h2> + <ol> + <li><a href="#HowBackupWorks">How backup works</a></li> + <li><a href="#Prerequisites">Prerequisites</a></li> + <li><a href="#Preparing">Preparing your device or emulator</a></li> + <li><a href="#TestingBackup">Testing backup</a></li> + <li><a href="#TestingRestore">Testing restore</a></li> + <li><a href="#Troubleshooting">Troubleshooting</a></li> + </ol> + +</div> +</div> + +<p>This page shows you how to manually trigger Auto Backup, Key/Value Backup, and restore operations to +ensure your app saves and restores data properly. + +<h2 id="HowBackupWorkso">How backup works</h2> +<p>The section describes various pieces in the Android backup framework and how they +interact with apps that support Auto Backup and Key/Value Backup. During the app +development phase, most of the inner working of the framework were abstracted away, so you didn't need to know this information. However, during the +testing phase, an understanding of these concepts is important. + +<p>The following diagram illustrates how data flows during backup and restore: + +<img src="images/backup-framework.png" alt="backup-framework"> + +<p>The <em>Backup Manager Service</em> is an Android system +service which orchestrates and initiates backup and restore operations. The service +is accessible through the {@link android.app.backup.BackupManager} +API. During a backup operation, the service queries your app for backup data, +then hands it to the <em>backup transport</em>, which then archives the data. +During a restore operation, the backup manager service retrieves the backup data +from the backup transport and restores the data to the device. + +<p><em>Backup Transports</em> are Android components that are responsible +for storing and retrieving backups. An Android device can have zero or more +backup transports, but only one of those transports can be marked active. The +available backup transports may differ from device to device (due to +customizations by device manufacturers and service providers), but most Google +Play enabled devices ship with the following transports: +</p><ul> +<li><strong>Google GMS Transport</strong>(default) - the active backup +transport on most devices, part of <a href="https://www.android.com/gms/">Google Mobile Services</a>. This documentation assumes that users are using the +Google GMS transport. This transport stores Auto Backup data in a private folder in the +user's Google Drive account. Key/Value Backup data is stored in the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>. +<li><strong>Local Transport</strong> - stores backup data locally on the device. +This transport is typically used for development/debugging purposes and is not +useful in the real world.</li></ul> + +<p>If a device does not have any backup transports, then the data cannot be +backed up. Your app is not adversely affected. + +<p class="caution"><strong>Caution:</strong> Because the backup transport +can differ from device to device, Android cannot guarantee the security +of your data while using backup. Be cautious about using backup to store +sensitive data, such as usernames and passwords. + +<h2 id="Prerequisites">Prerequisites</h2> +<p>You need to know a bit about the following tools: + +<ul> + <li><a href="{@docRoot}studio/command-line/adb.html">adb</a> +- to run commands on the device or emulator + <li><a href="{@docRoot}studio/command-line/bmgr.html">bmgr</a> - to +perform various backup and restore operations + <li><a href="{@docRoot}studio/command-line/logcat.html">logcat</a> +- to see the output of backup and restore operations.</li></ul> + +<h2 id="Preparing">Preparing your device or +emulator</h2> +<p>Prepare your device or emulator for backup testing by working through the +following checklist: +<ul> + <li>For Auto Backup, check that you are using a device or emulator running +Android 6.0 (API level 23) or higher.</li> + <li>For Key/Value Backup, check that you are using a device or emulator running +Android 2.2 (API level 8) or higher.</li> + <li>Check that backup and restore is enabled on the device or emulator. There +are two ways to check: <ul> + <li>On the device, go to <strong>Settings -> Backup & Restore</strong>. + <li>From adb shell, run <code>bmgr enable</code></li></ul> + <p>On physical devices, backup and restore is typically enabled during the +initial setup wizard. Emulators do not run the setup wizard, so don't forget to +enable backup and specify a backup account in device settings. + <li>Make sure the GMS Backup Transport is available and active by running the +command from adb shell: + <pre class="prettyprint">$ bmgr list transports</pre> + <p>Then, check the console for the following output: + <pre class="prettyprint">android/com.android.internal.backup.LocalTransport +* com.google.android.gms/.backup.BackupTransportService</pre> + <p>Physical devices without Google Play and emulators without Google APIs +might not include the GMS Backup Transport. This article assumes you are using +the GMS Backup Transport. You can test backup and restore with other backup +transports, but the procedure and output can differ. +</ul> + +<h2 id="TestingBackup">Testing backup</h2> +<p>To initiate a backup of your app, run the following command: + +<pre class="prettyprint">$ bmgr backupnow <PACKAGE></pre> + +<p>The <code>backupnow</code> command runs either a Key/Value Backup or Auto Backup depending on +the package's manifest declarations. Check logcat to see the output of the +backup procedure. For example: + +<pre class="prettyprint">D/BackupManagerService: fullTransportBackup() +I/GmsBackupTransport: Attempt to do full backup on <PACKAGE> + +---- or ---- + +V/BackupManagerService: Scheduling immediate backup pass +D/PerformBackupTask: starting key/value Backup of BackupRequest{pkg=<PACKAGE>} +</pre> + +<p>If the <code>backupnow</code> command is not available on your device, you need to run one +of the following commands: +<ul> + <li>For Auto Backups, run: <code>bmgr fullbackup <PACKAGE></code> + <li>For Key/Value Backups, schedule and run your backup with the following +commands: + <pre class="prettyprint">$ bmgr backup <PACKAGE> +$ bmgr run</pre> + <p><code>bmgr backup</code> adds your app to the Backup Manager's queue. <code>bmgr run</code> initiates the +backup operation, which forces the Backup Manager to perform all backup requests +that are in its queue. + </li></ul> + +<h2 id="TestingRestore">Testing restore</h2> +<p>To manually initiate a restore, run the following command: + +<pre class="prettyprint">$ bmgr restore <PACKAGE></pre> + +<p>Warning: This action stops your app and wipes its data before performing the +restore operation. + +<p>Then, check logcat to see the output of the restore procedure. For example: + +<pre class="prettyprint">V/BackupManagerService: beginRestoreSession: pkg=<PACKAGE> transport=null +V/RestoreSession: restorePackage pkg=<PACKAGE> token=368abb4465c5c683 +... +I/BackupManagerService: Restore complete. +</pre> + +<p>You also can test automatic restore for your app by uninstalling and +reinstalling your app either with <code>adb</code> or through the Google +Play Store app. + +<h2 id="Troubleshooting">Troubleshooting</h2> +<p><strong>Exceeded Quota</strong> + +<p>If you see the the following messages in logcat: + +<pre class="prettyprint">I/PFTBT: Transport rejected backup of <PACKAGE>, skipping + +--- or --- + +I/PFTBT: Transport quota exceeded for package: <PACKAGE> +</pre> + +<p>Your app has exceeded the quota and has been banned from backing up +data on this device. To lift the ban, either factory reset your device or change +the backup account. + +<p><strong>Full Backup Not Possible</strong> + +<p>If you see the the following message in logcat: + +<pre class="prettyprint">I/BackupManagerService: Full backup not currently possible -- key/value backup not yet run? +</pre> + +<p>The fullbackup operation failed because no Key/Value Backup operation has yet +occurred on the device. Trigger a Key/Value Backup with the command <code>bmgr +run </code>and then try again.
\ No newline at end of file diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd index aae0cbae99b3..4587ae4ec5db 100644 --- a/docs/html/guide/topics/resources/drawable-resource.jd +++ b/docs/html/guide/topics/resources/drawable-resource.jd @@ -1270,7 +1270,7 @@ the right edge, a right gravity clips the left edge, and neither clips both edge progressively reveal the image:</p> <pre> ImageView imageview = (ImageView) findViewById(R.id.image); -ClipDrawable drawable = (ClipDrawable) imageview.getDrawable(); +ClipDrawable drawable = (ClipDrawable) imageview.getBackground(); drawable.setLevel(drawable.getLevel() + 1000); </pre> diff --git a/docs/html/topic/performance/_book.yaml b/docs/html/topic/performance/_book.yaml index e053a2c1bdfe..4021e85c14aa 100644 --- a/docs/html/topic/performance/_book.yaml +++ b/docs/html/topic/performance/_book.yaml @@ -1,34 +1,61 @@ toc: -- title: Reducing Network Battery Drain - path: /topic/performance/power/network/index.html +- title: Optimizing for Battery Life + path: /topic/performance/power/index.html path_attributes: - name: description - value: Access the network while going easy on battery life. + value: Learn to make your app more battery-friendly. section: - - title: Collecting Network Traffic Data - path: /topic/performance/power/network/gather-data.html - - title: Analyzing Network Traffic Data - path: /topic/performance/power/network/analyze-data.html - - title: Optimizing User-Initiated Network Use - path: /topic/performance/power/network/action-user-traffic.html - - title: Optimizing Server-Initiated Network Use - path: /topic/performance/power/network/action-server-traffic.html - - title: Optimizing General Network Use - path: /topic/performance/power/network/action-any-traffic.html -- title: Implementing Doze - path: /training/monitoring-device-state/doze-standby.html + - title: Network Use and Battery Consumption + path: /topic/performance/power/network/index.html + section: + - title: Collecting Network Traffic Data + path: /topic/performance/power/network/gather-data.html + - title: Analyzing Data Traffic + path: /topic/performance/power/network/analyze-data.html + - title: Optimizing User-Initiated Network Use + path: /topic/performance/power/network/action-user-traffic.html + - title: Optimizing App-Initiated Network Use + path: topic/performance/power/network/action-app-traffic.html + - title: Optimizing Server-Initiated Network Use + path: /topic/performance/power/network/action-server-traffic.html + - title: Optimizing General Network Use + path: /topic/performance/power/network/action-any-traffic.html + - title: Doze and App Standby + path: /training/monitoring-device-state/doze-standby.html + path_attributes: + - name: description + value: Help ensure the device isn't depleting the battery when not in use. + - title: Battery Historian + path: /topic/performance/power/battery-historian.html +- title: Rendering + path: /topic/performance/rendering/index.html path_attributes: - name: description - value: Help ensure the device isn't depleting the battery when not in use. -- title: Launch-Time Performance - path: /topic/performance/launch-time.html -- title: Better Performance through Threading - path: /topic/performance/threads.html -- title: Optimizing View Hierarchies - path: /topic/performance/optimizing-view-hierarchies.html -- title: Background Optimization - path: /topic/performance/background-optimization.html + value: Speed up your app's rendering + section: + - title: Reducing Overdraw + path: /topic/performance/rendering/overdraw.html + - title: Performance and View Hierarchies + path: /topic/performance/rendering/optimizing-view-hierarchies.html + - title: Analyzing with Profile GPU Rendering + path: /topic/performance/rendering/profile-gpu.html - title: Intelligent Job-Scheduling path: /topic/performance/scheduling.html +- title: Background Optimization + path: /topic/performance/background-optimization.html - title: Reducing APK Size path: /topic/performance/reduce-apk-size.html +- title: Reducing Image Download Sizes + path: /topic/performance/network-xfer.html +- title: Launch-Time Performance + path: /topic/performance/launch-time.html +- title: Better Performance through Threading + path: /topic/performance/threads.html +- title: Manage Your App's Memory + path: /topic/performance/memory.html +- title: Overview of Memory Managemement + path: /topic/performance/memory-overview.html + path_attributes: + - name: description + value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices. + diff --git a/docs/html/topic/performance/images/app-rankings.png b/docs/html/topic/performance/images/app-rankings.png Binary files differnew file mode 100644 index 000000000000..9dd60e54735f --- /dev/null +++ b/docs/html/topic/performance/images/app-rankings.png diff --git a/docs/html/topic/performance/images/bars.png b/docs/html/topic/performance/images/bars.png Binary files differnew file mode 100644 index 000000000000..3afea465c975 --- /dev/null +++ b/docs/html/topic/performance/images/bars.png diff --git a/docs/html/topic/performance/images/beforeafterindexed.png b/docs/html/topic/performance/images/beforeafterindexed.png Binary files differnew file mode 100644 index 000000000000..dc7762ed42a4 --- /dev/null +++ b/docs/html/topic/performance/images/beforeafterindexed.png diff --git a/docs/html/topic/performance/images/comparison.png b/docs/html/topic/performance/images/comparison.png Binary files differnew file mode 100644 index 000000000000..18f204c31d1b --- /dev/null +++ b/docs/html/topic/performance/images/comparison.png diff --git a/docs/html/topic/performance/images/decisions.png b/docs/html/topic/performance/images/decisions.png Binary files differnew file mode 100644 index 000000000000..d4f21f8f770b --- /dev/null +++ b/docs/html/topic/performance/images/decisions.png diff --git a/docs/html/topic/performance/images/dropdown.png b/docs/html/topic/performance/images/dropdown.png Binary files differnew file mode 100644 index 000000000000..59ec6110e5ef --- /dev/null +++ b/docs/html/topic/performance/images/dropdown.png diff --git a/docs/html/topic/performance/images/generic-timeline.png b/docs/html/topic/performance/images/generic-timeline.png Binary files differnew file mode 100644 index 000000000000..04388b6f4abb --- /dev/null +++ b/docs/html/topic/performance/images/generic-timeline.png diff --git a/docs/html/topic/performance/images/moarparrots.png b/docs/html/topic/performance/images/moarparrots.png Binary files differnew file mode 100644 index 000000000000..ee10ec158936 --- /dev/null +++ b/docs/html/topic/performance/images/moarparrots.png diff --git a/docs/html/topic/performance/images/palette.png b/docs/html/topic/performance/images/palette.png Binary files differnew file mode 100644 index 000000000000..eb6be6b4246c --- /dev/null +++ b/docs/html/topic/performance/images/palette.png diff --git a/docs/html/topic/performance/images/parrot.png b/docs/html/topic/performance/images/parrot.png Binary files differnew file mode 100644 index 000000000000..7a8b86a97b1e --- /dev/null +++ b/docs/html/topic/performance/images/parrot.png diff --git a/docs/html/topic/performance/images/pug-visualization.png b/docs/html/topic/performance/images/pug-visualization.png Binary files differnew file mode 100644 index 000000000000..8270d0e37d1d --- /dev/null +++ b/docs/html/topic/performance/images/pug-visualization.png diff --git a/docs/html/topic/performance/images/pugspecificdata.png b/docs/html/topic/performance/images/pugspecificdata.png Binary files differnew file mode 100644 index 000000000000..1c2be837ba26 --- /dev/null +++ b/docs/html/topic/performance/images/pugspecificdata.png diff --git a/docs/html/topic/performance/images/s-generic-closeup.png b/docs/html/topic/performance/images/s-generic-closeup.png Binary files differnew file mode 100644 index 000000000000..6685d51a32a1 --- /dev/null +++ b/docs/html/topic/performance/images/s-generic-closeup.png diff --git a/docs/html/topic/performance/images/s-profiler-legend.png b/docs/html/topic/performance/images/s-profiler-legend.png Binary files differnew file mode 100644 index 000000000000..968fd381156a --- /dev/null +++ b/docs/html/topic/performance/images/s-profiler-legend.png diff --git a/docs/html/topic/performance/images/vq.gif b/docs/html/topic/performance/images/vq.gif Binary files differnew file mode 100644 index 000000000000..cbf6a3504059 --- /dev/null +++ b/docs/html/topic/performance/images/vq.gif diff --git a/docs/html/topic/performance/index.jd b/docs/html/topic/performance/index.jd index e08db15baa08..2b6b1972a03b 100644 --- a/docs/html/topic/performance/index.jd +++ b/docs/html/topic/performance/index.jd @@ -1,4 +1,4 @@ -page.title=Performance +page.title=Performance and Power page.article=true page.metaDescription=Improve your app's performance by learning how to optimize power consumption, launch times, and other important areas of performance. diff --git a/docs/html/topic/performance/memory-overview.jd b/docs/html/topic/performance/memory-overview.jd new file mode 100644 index 000000000000..58067d2be4b8 --- /dev/null +++ b/docs/html/topic/performance/memory-overview.jd @@ -0,0 +1,288 @@ +page.title=Overview of Android Memory Management +page.tags=ram,memory,paging,mmap + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> +<ol class="nolist"> + <li><a href="#gc">Garbage collection</a></li> + <li><a href="#SharingRAM">Sharing Memory</a></li> + <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li> + <li><a href="#RestrictingMemory">Restricting App Memory</a></li> + <li><a href="#SwitchingApps">Switching Apps</a></li> +</ol> +<h2>See Also</h2> +<ul> + <li><a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a> + </li> + <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a> + </li> +</ul> + +</div> +</div> + +<p> + The Android Runtime (ART) and Dalvik virtual machine use + <a href="http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a> + and <a href="http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a> + (mmapping) to manage memory. This means that any memory an app + modifies—whether by allocating + new objects or touching mmapped pages—remains resident in RAM and + cannot be paged out. The only way to release memory from an app is to release + object references that the app holds, making the memory available to the + garbage collector. + That is with one exception: any files + mmapped in without modification, such as code, + can be paged out of RAM if the system wants to use that memory elsewhere. +</p> + +<p> + This page explains how Android manages app processes and memory + allocation. For more information about how to manage memory more efficiently + in your app, see + <a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a>. +</p> + +<!-- Section 1 #################################################### --> + +<h2 id="gc">Garbage collection</h2> + +<p> + A managed memory environment, like the ART or Dalvik virtual machine, + keeps track of each memory allocation. Once it determines + that a piece of memory is no longer being used by the program, + it frees it back to the heap, without any intervention from the programmer. + The mechanism for reclaiming unused memory + within a managed memory environment + is known as <i>garbage collection</i>. Garbage collection has two goals: + find data objects in a program that cannot be accessed in the future; and + reclaim the resources used by those objects. +</p> + +<p> + Android’s memory heap is a generational one, meaning that there are + different buckets of allocations that it tracks, + based on the expected life and size of an object being allocated. + For example, recently allocated objects belong in the <i>Young generation</i>. + When an object stays active long enough, it can be promoted + to an older generation, followed by a permanent generation. +</p> + +<p> + Each heap generation has its own dedicated upper limit on the amount + of memory that objects there can occupy. Any time a generation starts + to fill up, the system executes a garbage collection + event in an attempt to free up memory. The duration of the garbage collection + depends on which generation of objects it's collecting + and how many active objects are in each generation. +</p> + +<p> + Even though garbage collection can be quite fast, it can still + affect your app's performance. You don’t generally control + when a garbage collection event occurs from within your code. + The system has a running set of criteria for determining when to perform + garbage collection. When the criteria are satisfied, + the system stops executing the process and begins garbage collection. If + garbage collection occurs in the middle of an intensive processing loop + like an animation or during music playback, it can increase processing time. + This increase can potentially push code execution in your app past the + recommended 16ms threshold for efficient and smooth frame rendering. +</p> + +<p> + Additionally, your code flow may perform kinds of work that + force garbage collection events to occur + more often or make them last longer-than-normal. + For example, if you allocate multiple objects in the + innermost part of a for-loop during each frame of an alpha + blending animation, you might pollute your memory heap with a + lot of objects. + In that circumstance, the garbage collector executes multiple garbage + collection events and can degrade the performance of your app. +</p> + +<p> + For more general information about garbage collection, see + <a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)" + class="external-link">Garbage collection</a>. +</p> + +<!-- Section 2 #################################################### --> + +<h2 id="SharingRAM">Sharing Memory</h2> + +<p> + In order to fit everything it needs in RAM, + Android tries to share RAM pages across processes. It + can do so in the following ways: +</p> + +<ul> + <li> + Each app process is forked from an existing process called Zygote. + The Zygote process starts when the system boots and loads common + framework code and resources + (such as activity themes). To start a new app process, + the system forks the Zygote process then + loads and runs the app's code in the new process. + This approach allows most of the RAM pages allocated for + framework code and resources to be shared across all app processes. + </li> + + <li> + Most static data is mmapped into a process. + This technique allows data to be shared + between processes, and also allows it to be paged + out when needed. Example static data include: + Dalvik code (by placing it in a pre-linked <code>.odex</code> + file for direct mmapping), app resources + (by designing the resource table to be a structure + that can be mmapped and by aligning the zip + entries of the APK), and traditional project + elements like native code in <code>.so</code> files. + </li> + + <li> + In many places, Android shares the same dynamic + RAM across processes using explicitly allocated + shared memory regions (either with ashmem or gralloc). + For example, window surfaces use shared + memory between the app and screen compositor, and + cursor buffers use shared memory between the + content provider and client. + </li> +</ul> + +<p> + Due to the extensive use of shared memory, determining + how much memory your app is using requires + care. Techniques to properly determine your app's + memory use are discussed in + <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>. +</p> + +<!-- Section 3 #################################################### --> + +<h2 id="AllocatingRAM">Allocating and Reclaiming App Memory</h2> + +<p> + The Dalvik heap is constrained to a + single virtual memory range for each app process. This defines + the logical heap size, which can grow as it needs to + but only up to a limit that the system defines + for each app. +</p> + +<p> + The logical size of the heap is not the same as + the amount of physical memory used by the heap. + When inspecting your app's heap, Android computes + a value called the Proportional Set Size (PSS), + which accounts for both dirty and clean pages + that are shared with other processes—but only in an + amount that's proportional to how many apps share + that RAM. This (PSS) total is what the system + considers to be your physical memory footprint. + For more information about PSS, see the + <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a> + guide. +</p> + +<p> + The Dalvik heap does not compact the logical + size of the heap, meaning that Android does not + defragment the heap to close up space. Android + can only shrink the logical heap size when there + is unused space at the end of the heap. However, + the system can still reduce physical memory used by the heap. + After garbage collection, Dalvik + walks the heap and finds unused pages, then returns + those pages to the kernel using madvise. So, paired + allocations and deallocations of large + chunks should result in reclaiming all (or nearly all) + the physical memory used. However, + reclaiming memory from small allocations can be much + less efficient because the page used + for a small allocation may still be shared with + something else that has not yet been freed. + +</p> + +<!-- Section 4 #################################################### --> + +<h2 id="RestrictingMemory">Restricting App Memory</h2> + +<p> + To maintain a functional multi-tasking environment, + Android sets a hard limit on the heap size + for each app. The exact heap size limit varies + between devices based on how much RAM the device + has available overall. If your app has reached the + heap capacity and tries to allocate more + memory, it can receive an {@link java.lang.OutOfMemoryError}. +</p> + +<p> + In some cases, you might want to query the + system to determine exactly how much heap space you + have available on the current device—for example, to + determine how much data is safe to keep in a + cache. You can query the system for this figure by calling + {@link android.app.ActivityManager#getMemoryClass() }. + This method returns an integer indicating the number of + megabytes available for your app's heap. +</p> + +<!-- Section 5 #################################################### --> + +<h2 id="SwitchingApps">Switching apps</h2> + +<p> + When users switch between apps, + Android keeps apps that + are not foreground—that is, not visible to the user or running a + foreground service like music playback— + in a least-recently used (LRU) cache. + For example, when a user first launches an app, + a process is created for it; but when the user + leaves the app, that process does <em>not</em> quit. + The system keeps the process cached. If + the user later returns to the app, the system reuses the process, thereby + making the app switching faster. +</p> + +<p> + If your app has a cached process and it retains memory + that it currently does not need, + then your app—even while the user is not using it— + affects the system's + overall performance. As the system runs low on memory, + it kills processes in the LRU cache + beginning with the process least recently used. The system also + accounts for processes that hold onto the most memory + and can terminate them to free up RAM. +</p> + +<p class="note"> + <strong>Note:</strong> When the system begins killing processes in the + LRU cache, it primarily works bottom-up. The system also considers which + processes consume more memory and thus provide the system + more memory gain if killed. + The less memory you consume while in the LRU list overall, + the better your chances are + to remain in the list and be able to quickly resume. +</p> + +<p> + For more information about how processes are cached while + not running in the foreground and how + Android decides which ones + can be killed, see the + <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a> + guide. +</p> diff --git a/docs/html/topic/performance/memory.jd b/docs/html/topic/performance/memory.jd new file mode 100644 index 000000000000..ef1c4ae0aeea --- /dev/null +++ b/docs/html/topic/performance/memory.jd @@ -0,0 +1,593 @@ +page.title=Manage Your App's Memory +page.tags=ram,low memory,OutOfMemoryError,onTrimMemory + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> +<ol> + <li><a href="#monitor">Monitor Available Memory and Memory Usage</a> + <ul> + <li><a href="#AnalyzeRam">Tools for analyzing RAM usage</a></li> + <li><a href="#release">Release memory in response to events</a></li> + <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li> + </ul> + </li> + <li><a href="#code">Use More Efficient Code Constructs</a> + <ul> + <li><a href="#Services">Use services sparingly</a></li> + <li><a href="#DataContainers">Use optimized data containers</a></li> + <li><a href="#Abstractions">Be careful with code abstractions</a></li> + <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li> + <li><a href="#churn">Avoid memory churn</a></li> + </ul> + </li> + <li><a href="#remove">Remove Memory-Intensive Resources and Libraries</a> + <ul> + <li><a href="#reduce">Reduce overall APK size</a></li> + <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li> + <li><a href="#ExternalLibs">Be careful about using external libraries</a></li> + </ul> + </li> +</ol> +<h2>See Also</h2> +<ul> + <li><a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a> + </li> + <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a> + </li> + <li><a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a></li> +</ul> + +</div> +</div> + +<!-- INTRO #################################################### --> + +<p> + Random-access memory (RAM) is a valuable + resource in any software development environment, but + it's even more valuable on a mobile operating system + where physical memory is often constrained. + Although both the Android Runtime (ART) and Dalvik virtual machine perform + routine garbage collection, this does not mean you can ignore + when and where your app allocates and releases memory. + You still need to avoid + introducing memory leaks, usually caused by holding onto + object references in static member variables, and + release any {@link java.lang.ref.Reference} objects at the appropriate + time as defined by + lifecycle callbacks. +</p> + +<p> + This page explains how you can + proactively reduce memory usage within your app. + For more information about general + practices to clean up your resources when programming in Java, + refer to other books or online + documentation about managing resource references. + If you’re looking for information about how to + analyze memory in a running app, read + <a href="#AnalyzeRam">Tools for analyzing RAM usage</a>. + For more detailed information about how the Android Runtime and Dalvik + virtual machine manage memory, see the + <a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>. +</p> + +<!-- Section 1 #################################################### --> + +<h2 id="monitor">Monitor Available Memory and Memory Usage</h2> + +<p> + The Android framework, Android Studio, and Android SDK + can help you analyze and adjust your app's memory usage. + The Android framework + exposes several APIs that allow your app to reduce its memory usage + dynamically during runtime. Android Studio and the Android SDK + contain several tools that allow you to investigate how your + app uses memory. +</p> + +<!-- Section 1.1 #################################################### --> + +<h3 id="AnalyzeRam">Tools for analyzing RAM usage</h3> + +<p> + Before you can fix the memory usage problems in your app, you first need + to find them. Android Studio and the Android SDK include several tools + for analyzing memory usage in your app: +</p> + +<ol> + <li> + The Device Monitor has a Dalvik Debug Monitor Server (DDMS) tool that allows + you to inspect memory allocation within your app process. + You can use this information to understand how your + app uses memory overall. For example, you can force a garbage collection + event and then view the types of objects that remain in memory. You can + use this information to identify operations or actions within your app + that allocate or leave excessive amounts of objects in memory. + + <p>For more information about how to use the DDMS tool, see + <a href="/studio/profile/ddms.html">Using DDMS</a>. + </p> + </li> + + <li> + The Memory Monitor in Android Studio shows you how your app allocates + memory over the course of a single session. + The tool shows a graph of available + and allocated Java memory over time, including garbage collection events. + You can also initiate garbage collection events and take a snapshot of + the Java heap while your app runs. The output from the Memory Monitor tool + can help you identify points when your app experiences excessive garbage + collection events, leading to app slowness. + <p> + For more information about how to use Memory Monitor tool, see + <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewHeap">Viewing Heap Updates</a>. + </p> + </li> + + <li> + Garbage collection events also show up in the Traceview viewer. Traceview + allows you to view trace log files as both a timeline and as a profile + of what happened within a method. You can use this tool to determine + what code was executing when a garbage collection event occurred. + <p> + For more information about how to use the Traceview viewer, see + <a href="https://developer.android.com/studio/profile/traceview.html">Profiling with Traceview and dmtracedump</a>. + </p> + </li> + + <li> + The Allocation Tracker tool in Android Studio gives you a detailed look + at how your app allocates memory. + The Allocation Tracker records an app's memory allocations and lists + all allocated objects within the profiling snapshot. You can use this + tool to track down parts of your code that allocate too many objects. + + <p> + For more information about how to use the Allocation Tracker tool, see + <a href="{docRoot}studio/profile/allocation-tracker-walkthru.html">Allocation Tracker Walkthrough</a>. + </p> + </li> + +</ol> + +<!-- Section 1.2 #################################################### --> + +<h3 id="release">Release memory in response to events</h3> + +<p> + An Android device can run with varying amounts of free memory + depending on the physical amount of RAM on the device and how the user + operates it. The system broadcasts signals to indicate when it is under + memory pressure, and apps should listen for these signals and adjust + their memory usage as appropriate. +</p> + +</p> + You can use the {@link android.content.ComponentCallbacks2} API + to listen for these signals and then adjust your memory + usage in response to app lifecycle + or device events. The + {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} + method allows your app to listen for memory related events when the app runs + in the foreground (is visible) and when it runs in the background. +</p> + +<p> + To listen for these events, implement the {@link + android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} + callback in your {@link android.app.Activity} + classes, as shown in the following code snippet. +</p> + +<pre class="prettyprint"> +import android.content.ComponentCallbacks2; +// Other import statements ... + +public class MainActivity extends AppCompatActivity + implements ComponentCallbacks2 { + + // Other activity code ... + + /** + * Release memory when the UI becomes hidden or when system resources become low. + * @param level the memory-related event that was raised. + */ + public void onTrimMemory(int level) { + + // Determine which lifecycle or system event was raised. + switch (level) { + + case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN: + + /* + Release any UI objects that currently hold memory. + + The user interface has moved to the background. + */ + + break; + + case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE: + case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW: + case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL: + + /* + Release any memory that your app doesn't need to run. + + The device is running low on memory while the app is running. + The event raised indicates the severity of the memory-related event. + If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will + begin killing background processes. + */ + + break; + + case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND: + case ComponentCallbacks2.TRIM_MEMORY_MODERATE: + case ComponentCallbacks2.TRIM_MEMORY_COMPLETE: + + /* + Release as much memory as the process can. + + The app is on the LRU list and the system is running low on memory. + The event raised indicates where the app sits within the LRU list. + If the event is TRIM_MEMORY_COMPLETE, the process will be one of + the first to be terminated. + */ + + break; + + default: + /* + Release any non-critical data structures. + + The app received an unrecognized memory level value + from the system. Treat this as a generic low-memory message. + */ + break; + } + } +} +</pre> + +<p> + The + {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} + callback was added in Android 4.0 (API level 14). For earlier versions, + you can use the + {@link android.content.ComponentCallbacks#onLowMemory()} + callback as a fallback for older versions, which is roughly equivalent to the + {@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event. +</p> + +<!-- Section 1.3 #################################################### --> + +<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3> + +<p> + To allow multiple running processes, Android sets a hard limit + on the heap size alloted for each app. The exact heap size limit varies + between devices based on how much RAM the device + has available overall. If your app has reached the heap capacity and + tries to allocate more + memory, the system throws an {@link java.lang.OutOfMemoryError}. +</p> + +<p> + To avoid running out of memory, you can to query the system to determine + how much heap space you have available on the current device. + You can query the system for this figure by calling + {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}. + This returns an + {@link android.app.ActivityManager.MemoryInfo } object that provides + information about the device's + current memory status, including available memory, total memory, and + the memory threshold—the memory level below which the system begins + to kill processes. The + {@link android.app.ActivityManager.MemoryInfo } class also exposes a simple + boolean field, + {@link android.app.ActivityManager.MemoryInfo#lowMemory } + that tells you whether the device is running low on memory. +</p> + +<p> + The following code snippet shows an example of how you can use the + {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}. + method in your application. +</p> + +<pre class="prettyprint"> +public void doSomethingMemoryIntensive() { + + // Before doing something that requires a lot of memory, + // check to see whether the device is in a low memory state. + ActivityManager.MemoryInfo memoryInfo = getAvailableMemory(); + + if (!memoryInfo.lowMemory) { + // Do memory intensive work ... + } +} + +// Get a MemoryInfo object for the device's current memory status. +private ActivityManager.MemoryInfo getAvailableMemory() { + ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE); + ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); + activityManager.getMemoryInfo(memoryInfo); + return memoryInfo; +} +</pre> + +<!-- Section 2 #################################################### --> + +<h2 id="code">Use More Memory-Efficient Code Constructs</h2> + +<p> + Some Android features, Java classes, and code constructs tend to + use more memory than others. You can minimize how + much memory your app uses by choosing more efficient alternatives in + your code. +</p> + +<!-- Section 2.1 #################################################### --> + +<h3 id="Services">Use services sparingly</h3> + +<p> + Leaving a service running when it’s not needed is + <strong>one of the worst memory-management + mistakes</strong> an Android app can make. If your app needs a + <a href="{@docRoot}guide/components/services.html">service</a> + to perform work in the background, do not keep it running unless + it needs to run a job. Remember to stop your service when it has completed + its task. Otherwise, you can inadvertently cause a memory leak. +</p> + +<p> + When you start a service, the system prefers to always keep the process + for that service running. This behavior + makes services processes very expensive + because the RAM used by a service remains unavailable to other processes. + This reduces the number of cached processes that the system can keep in + the LRU cache, making app switching less efficient. It can even lead to + thrashing in the system when memory is tight and the system can’t + maintain enough processes to host all the services currently running. +</p> + +<p> + You should generally avoid use of persistent services because of + the on-going demands they place on available memory. Instead, we + recommend that you use an alternative implementation + such as {@link android.app.job.JobScheduler}. For more information about + how to use {@link android.app.job.JobScheduler} to schedule background + processes, see + <a href="/topic/performance/background-optimization.html">Background Optimizations</a>. +<p> + If you must use a service, the + best way to limit the lifespan of your service is to use an {@link + android.app.IntentService}, which finishes + itself as soon as it's done handling the intent that started it. + For more information, read + <a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>. +</p> + +<!-- Section 2.2 #################################################### --> + +<h3 id="DataContainers">Use optimized data containers</h3> + +<p> + Some of the classes provided by the programming language are not optimized for + use on mobile devices. For example, the generic + {@link java.util.HashMap} implementation can be quite memory + inefficient because it needs a separate entry object for every mapping. +</p> + +<p> + The Android framework includes several optimized data containers, including + {@link android.util.SparseArray}, {@link android.util.SparseBooleanArray}, + and {@link android.support.v4.util.LongSparseArray}. + For example, the {@link android.util.SparseArray} classes are more + efficient because they avoid the system's need to + <acronym title="Automatic conversion from primitive types to object classes (such as int to Integer)">autobox</acronym> + the key and sometimes value (which creates yet another object or + two per entry). +</p> + +<p> + If necessary, you can always switch to raw arrays for a really lean data + structure. +</p> + +<!-- Section 2.3 #################################################### --> + +<h3 id="Abstractions">Be careful with code abstractions</h3> + +<p> + Developers often use abstractions simply as a good programming practice, + because abstractions can improve code flexibility and maintenance. + However, abstractions come at a significant cost: + generally they require a fair amount more code that + needs to be executed, requiring more time and + more RAM for that code to be mapped into memory. + So if your abstractions aren't supplying a + significant benefit, you should avoid them. +</p> + +<p> + For example, enums often require more than twice as much memory as static + constants. You should strictly avoid using enums on Android. +</p> + +<!-- Section 2.4 #################################################### --> + +<h3 id="NanoProto">Use nano protobufs for serialized data</h3> + +<p> + <a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol buffers</a> + are a language-neutral, platform-neutral, extensible mechanism + designed by Google for serializing structured data—similar to XML, but + smaller, faster, and simpler. If you decide to use + protobufs for your data, you should always use nano protobufs in your + client-side code. Regular protobufs generate extremely verbose code, which + can cause many kinds of problems in your app such as + increased RAM use, significant APK size increase, and slower execution. +</p> + +<p> + For more information, see the "Nano version" section in the + <a href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt" +class="external-link">protobuf readme</a>. +</p> + +<!-- Section 2.5 #################################################### --> + +<h3 id="churn">Avoid memory churn</h3> + +<p> + As mentioned previously, garbage collections events don't normally affect + your app's performance. However, many garbage collection events that occur + over a short period of time can quickly eat up your frame time. The more time + that the system spends on garbage collection, the less time it has to do + other stuff like rendering or streaming audio. +</p> + +<p> + Often, <em>memory churn</em> can cause a large number of + garbage collection events to occur. In practice, memory churn describes the + number of allocated temporary objects that occur in a given amount of time. +</p> + +<p> + For example, you might allocate multiple temporary objects within a + <code>for</code> loop. Or you might create new + {@link android.graphics.Paint} or {@link android.graphics.Bitmap} + objects inside the + {@link android.view.View#onDraw(android.graphics.Canvas) onDraw()} + function of a view. + In both cases, the app creates a lot of objects quickly at high volume. + These can quickly consume all the available memory in the young generation, + forcing a garbage collection event to occur. +</p> + +<p> + Of course, you need to find the places in your code where + the memory churn is high before you can fix them. Use the tools discussed in + <a href="#AnalyzeRam">Analyze your RAM usage</a> +</p> + +<p> + Once you identify the problem areas in your code, try to reduce the number of + allocations within performance critical areas. Consider moving things out of + inner loops or perhaps moving them into a + <a href="https://en.wikipedia.org/wiki/Factory_method_pattern" class="external-link">Factory</a> + based allocation structure. +</p> + +<!-- Section 3 #################################################### --> + +<h2 id="remove">Remove Memory-Intensive Resources and Libraries</h2> + +<p> + Some resources and libraries within your code can gobble up memory without + you knowing it. Overall size of your APK, including third-party libraries + or embedded resources, can affect how much memory your app consumes. You can + improve your app's memory consumption by removing any redundant, unnecessary, + or bloated components, resources, or libraries from your code. +</p> + +<!-- Section 3.1 #################################################### --> + +<h3 id="reduce">Reduce overall APK size</h3> + +<p> + You can significantly reduce your app's memory usage by reducing the overall + size of your app. Bitmap size, resources, animation frames, and third-party + libraries can all contribute to the size of your APK. + Android Studio and the Android SDK provide multiple tools + to help you reduce the size of your resources and external dependencies. +</p> + +<p> + For more information about how to reduce your overall APK size, see + <a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a>. +</p> + +<!-- Section 3.2 #################################################### --> + +<h3 id="DependencyInjection">Use caution with dependency injection frameworks</h3> + +<p> + Dependency injection framework such as + <a href="https://code.google.com/p/google-guice/" class="external-link">Guice</a> + or + <a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a> + can simplify the code you write and provide an adaptive environment + that's useful for testing and other configuration changes. However, dependency + frameworks aren't always optimized for mobile devices. +</p> + +<p> + For example, these frameworks tend to initialize processes by + scanning your code for annotations. This which can require significant + amounts of your code to be mapped into RAM unnecessarily. The system + allocates these mapped pages into clean memory so Android can drop them; yet + that can't happen until the pages have remained in memory for a long period + of time. + </p> + +<p> + If you need to use a dependency injection framework in your app, consider + using + <a class="external-link" href="http://google.github.io/dagger/">Dagger</a> + instead. For example, Dagger does not use reflection to scan your app's code. + Dagger's strict implementation means that it can be used in Android apps + without needlessly increasing memory usage. +</p> + +<!-- Section 3.3 #################################################### --> + +<h3 id="ExternalLibs">Be careful about using external libraries</h3> + +<p> + External library code is often not written for mobile environments and + can be inefficient when used + for work on a mobile client. When you decide to use an + external library, you may need to optimize that library for mobile devices. + Plan for that work up-front and analyze the library in terms of code size and + RAM footprint before deciding to use it at all. +</p> + +<p> + Even some mobile-optimized libraries can cause problems due to differing + implementations. For example, one library may use nano protobufs + while another uses micro protobufs, resulting in two different protobuf + implementations in your app. This can happen with different + implementations of logging, analytics, image loading frameworks, + caching, and many other things you don't expect. +</p> + +<p> + Although <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> can + help to remove APIs and resources with the right flags, it can't remove a + library's large internal dependencies. The features that you want in these + libraries may require lower-level dependencies. This becomes especially + problematic when you use an {@link android.app.Activity } subclass from a + library (which will tend to have wide swaths of dependencies), + when libraries use reflection (which is common and means you need to spend a + lot of time manually tweaking ProGuard to get it to work), and so on. +</p> + +<p> + Also avoid using a shared library for just one or two features out of dozens. + You don't want to pull in a large amount of code and overhead that + you don't even use. When you consider whether to use a library, look for + an implementation that strongly matches what you need. Otherwise, you might + decide to create your own implementation. +</p> + diff --git a/docs/html/topic/performance/network-xfer.jd b/docs/html/topic/performance/network-xfer.jd new file mode 100644 index 000000000000..7fe5594ca899 --- /dev/null +++ b/docs/html/topic/performance/network-xfer.jd @@ -0,0 +1,374 @@ +page.title=Reducing Image Download Sizes +page.metaDescription=Improve network performance by optimizing image size. + +meta.tags="performance" +page.tags="performance" + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> + <ol> + + <li> + <a href="#uif">Understanding Image Formats</a> + <ul> + <li><a href="#png">PNG</a></li> + <li><a href="#jpg">JPG</a></li> + <li><a href="#webp">WebP</a></li> + </ul> + </li> + <li> + <a href="#sf">Selecting a Format</a></li> + <li><a href="#doqv">Determining Optimal Quality Values</a> + <ul> + <li><a href="#sv">Scalar Values (JPG, WebP only)</a></li> + <li><a href="#butter">Butteraugli</a></li> + </ul> + </li> + <li><a href="#sizes">Serving Sizes</a></li> + </ol> + </div> +</div> + +<p> +Most download traffic consists of images. As a result, the smaller you can make +your downloadable images, the better a network experience your app can provide +for users. This page provides guidance on making image files smaller and more +network-friendly. +</p> + +<h2 id="uif">Understanding Image Formats</h2> + +<p>Android apps typically use images that are in one or more of the following file +formats: PNG, JPG, and WebP. For each of these formats, there are steps you can +take to reduce image sizes. +</p> + +<h3 id="png">PNG</h3> + +<p> +A key to making your PNG files smaller is reducing the number of unique +colors used in each row of pixels that comprises the image. By using fewer +colors, you improve the compression potential at all of the other stages of +the pipeline. +</p> + +<p> +Reducing the number of unique colors makes a significant difference because PNG +compression effectiveness is partly a function of the degree to which +horizontally adjacent pixel colors vary. Thus, reducing the number of unique +colors in each row of your PNG images can help in reducing their file sizes. +</p> + +<p> +When deciding whether to pursue this strategy, you should keep in mind that +reducing the number of unique colors effectively amounts to applying a lossy +encoding stage to the image. However, an encoding tool may not be a good +judge of how bad a seemingly small error looks to the human eye. Therefore, +you should perform this work manually in order to help ensure +the right balance between efficient compression and acceptable image quality. +</p> + +<p> +There are two particularly useful approaches you can take: striving for indexed +formats, and applying vector quantization. +</p> + + +<h4 id="strive">Strive for indexed formats</h4> + +<p> +Any attempt at color reduction should start with trying to optimize your colors +so that you can use the INDEXED format when exporting the image as a PNG. The +INDEXED color mode works by choosing the best 256 colors to use, and replacing +all pixel values with indices into that color palette. The result is a +reduction from 16 million (potential) colors to only 256 colors: from 3 (without +transparency) or 4 (with transparency) bytes per pixel to 1 byte per pixel. +This change is a significant first-step file size reduction. +</p> + +<p> +Figure 1 shows shows an image and its indexed variant. +</p> + + <img src="{@docRoot}topic/performance/images/beforeafterindexed.png"> + <p class="img-caption"> +Figure 1. An image before and after conversion to the INDEXED format. + </p> + + +<p> +Figure 2 shows the color palette for the image in Figure 1: +</p> + + <img src="{@docRoot}topic/performance/images/palette.png"> + <p class="img-caption"> +Figure 2. The color palette for the image in Figure 1. + </p> + +<p> +Representing your image as a paletted image goes a long way toward +significantly improving the file size, so it's worth investigating if the +majority of your images can be converted. +</p> + +<p> +Of course, not every image can be accurately represented with only 256 colors. +Some images, for example, might need 257, 310, 512, or 912 colors to +look correct. In such cases, vector quantization can also be helpful. +</p> + +<h4 id="vq">Vector quantization</h4> + +<p> +The process of creating an indexed image may be better described as vector +quantization (VQ). VQ serves as a rounding process for multidimensional +numbers. In this process, all the colors in your image get grouped based upon +their similarity. For a given group, all colors in that group are replaced by a +single <em>center point</em> value, which minimizes error for colors in that +cell (or "site" if you're using the Voronoi terminology). In Figure 3, +the green dots represent input colors, and the red dots are the center points +that replace the input colors. Each cell is bounded by blue lines. +</p> + + <img src="{@docRoot}topic/performance/images/vq.gif"> + <p class="img-caption"> +Figure 3. Applying vector quantization to the colors in an image. +</p> + +<p> +The result of applying VQ to an image reduces the number of unique colors, +replacing each group of colors with a single color that's "pretty close" +in visual quality. +</p> + +<p> +This technique also allows you to define the maximum number of unique colors in +your image. For example, Figure 4 shows the a parrot head in 16.7 million colors +(24 bits per pixel, or bpp) alongside a version that only allows only +16 (3 bpp) unique colors to be used. +</p> + + <img src="{@docRoot}topic/performance/images/parrot.png"> + <p class="img-caption"> +Figure 4. Image before and after application of vector quantification. + </p> + +<p> +Immediately, you can see that there's a loss of quality; most of the gradient +colors have been replaced, imparting a banding effect to the image. This image +needs more than 16 unique colors. +</p> + +<p> +Setting up a VQ step in your pipeline can help you get a better sense of the +true number of unique colors that your image uses, and can help you reduce them +significantly. There are a number of readily available tools that you can use +to help you implement this technique. +</p> + +<h3 id="jpg">JPG</h3> + +<p> +If you are using JPG images, there are several small changes you can make that +potentially provide significant file-size savings. These include: +</p> + +<ul> + <li> +Producing a smaller file size through different encoding methods (without +impacting quality). + </li> + + <li> +Adjusting quality slightly in order to yield better compression. + </li> +</ul> + +<p>Pursuing these strategies can often net you file-size reductions of up to +25%. +</p> + +<p> +When choosing tools, remember that photo exporting tools can +insert unnecessary metadata, such as GPS information, into your images. At +a minimum, try to leverage existing tools to help strip out this information +from your files. +</p> + +<h3 id="webp">WebP</h3> + +<p> +WebP is a newer image format supported from Android 4.2.1 (API level 17). This +format provides superior lossless and lossy compression for images on the web. +Using WebP, developers can create smaller, richer images. WebP lossless image +files are, on average, +<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#conclusions"> +26% smaller</a> than PNGs. These image files also support +transparency (also known as alpha channel) at a cost of just +<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#results"> +22% more</a> bytes. +</p> + +<p> +WebP lossy images are +<a href="https://developers.google.com/speed/webp/docs/webp_study#experiment_1_webp_vs_jpeg_at_equal_ssim_index"> +25-34% smaller</a> than comparable JPG images at equivalent +<a href="https://en.wikipedia.org/wiki/Structural_similarity">SSIM</a> +quality indices. For cases when lossy RGB compression is acceptable, lossy +WebP also supports transparency, typically producing file sizes 3 times smaller +than PNG. +</p> + +<p> +For more information about WebP, visit the +<a href="https://developers.google.com/speed/webp/">WebP site</a>. +</p> + +<h2 id="sf">Selecting a Format</h2> + +<p> +Different image formats are suitable for different types of images. JPG and PNG +have very different compression processes, and they produce quite different +results. +</p> + +<p> +The decision between PNG and JPG often comes down to the complexity of the +image itself. Figure 5 shows two images that come out quite differently +depending on which compression scheme the developer applies. The image on the +left has many small details, and thus compresses more efficiently with JPG. The +image on the right, with runs of the same color, compresses more efficiently +with PNG. +</p> + + <img src="{@docRoot}topic/performance/images/comparison.png"> + <p class="img-caption"> +Figure 5. Suitable cases for JPG vs. PNG + </p> + + +<p> +WebP as a format can support both lossy and lossless modes, making it an ideal +replacement for both PNG and JPG. The only thing to keep in mind is that it +only has native support on devices running Android 4.2.1 (API level 17) and +higher. Fortunately, the large +<a +href="https://developer.android.com/about/dashboards/index.html#Platform"> +majority of devices</a> satisfy that requirement. +</p> + +<p> +Figure 6 provides a simple visualization to help you decide which compression +scheme to use. +</p> + + <img src="{@docRoot}topic/performance/images/decisions.png"> + <p class="img-caption"> +Figure 6. Deciding on a compression scheme + </p> + +<h2 id="doqv">Determining Optimal Quality Values</h2> + +<p> +There are several techniques you can use to achieve the right balance between +compression and image quality. One technique uses scalar values and therefore +only works for JPG and WebP. The other technique takes advantage of the +Butteraugli library, and is usable for all image formats. +</p> + +<h3 id="sv">Scalar values (JPG and WebP only)</h3> + +<p> +The power of JPG and WebP comes from the fact that you can use a scalar value +to balance quality against file size. The trick is finding out what the correct +quality value is for your image. Too low a quality level produces a small file +at the cost of image quality. Too high a quality level increases file size +without providing a noticeable benefit to the user. +</p> + +<p> +The most straightforward solution is to pick some non-maximum value, and use +that value. However, be aware that the quality value affects every image +differently. While a quality of 75%, for example, may look fine on most images, +there may be some cases do not fare as well. You should make sure to test your +chosen maximum value against a representative sample of images. Also, make +sure to perform all of your tests against the original images, and not on +compressed versions. +</p> + +<p> +For large media applications that upload and re-send millions of JPGs a day, +hand-tuning for each asset is impractical. You might address this challenge by +specifying several different quality levels, according to image category. For +example, you might set 35% as the quality setting for thumbnails, since a +smaller image hides more compression artifacts. +</p> + +<h3 id="butter">Butteraugli</h4> + +<p> +The Butteraugli project is a library to test an image's Psychovisual Error +Threshold: the point at which a viewer starts to notice image degradation. In +other words, this project attempts to quantify how distorted your compressed +image is. +</p> + +<p> +Butteraugli allows you to define a goal for visual quality, and then run PNG, +JPG, WebP lossy, and WebP lossless compressions. You can then choose the image +that is the best balance of file size and Butteraugli level. Figure 7 shows an +example of how Butteraugli was used to find the minimal JPG quality level +before the visual distortion was high enough for a user could perceive a +problem; the result is a roughly 65% reduction in file size. +</p> + + <img src="{@docRoot}topic/performance/images/moarparrots.png"> + <p class="img-caption"> +Figure 7. An image before and after application of Butteraugli technology. + </p> + +<p> +Butteraugli allows you to proceed based on either output or input. That is, you +can look for the lowest quality setting before a user perceives noticeable +distortion in the resulting image, or you can iteratively set image-distortion +levels to learn their associated quality levels. +</p> + +<h2 id="sizes">Serving Sizes</h2> + +<p> +It is tempting to keep only a single resolution of an image on a server. When a +device accesses the image, the server serves it at that one resolution and +leaves downscaling to the device. +</p> + +<p> +This solution is convenient for the developer, but potentially painful for the +user, because the solution forces the user to download much more data than they +need. + +You should instead store multiple sizes of images, and serve the size that is +most appropriate for a particular use case. For example, for a thumbnail, +serving an actual thumbnail image instead of serving and downscaling a +full-size version consumes much less network bandwidth +</p> + +</p> +This approach is good for download speed, and is less costly for users who may +be using limited or metered data plans. Proceeding like this also results in +the image's taking less space on the device and in main memory. In the +case of large images, such as 4K ones, this approach also saves the device +from having to resize images before loading them. +</p> + +<p> +Implementing this approach requires that you have a backend image service to +provide images at various resolutions with proper caching. There are existing +services that can provide help with this task. For example, +<a href="https://cloud.google.com/appengine/">App Engine</a> comes +with image resizing functionality already installed. +</p> diff --git a/docs/html/topic/performance/power/battery-historian.jd b/docs/html/topic/performance/power/battery-historian.jd new file mode 100644 index 000000000000..79ea59d21419 --- /dev/null +++ b/docs/html/topic/performance/power/battery-historian.jd @@ -0,0 +1,247 @@ +page.title=Analyzing Power Use with Battery Historian +page.metaDescription=Improve network performance by optimizing image size. + +meta.tags="power" +page.tags="power" + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> + <ol> + <li> + <a href="#sv">System-wide View</a> + </li> + <li> + <a href="#asd">App-Specific Data</a> + </li> + <li> + <a href="#usecases">Other Cases Where Battery Historian Can Help</a> + </li> + </ol> +<h2>See also</h2> + <ol> + <li> + <a href="https://github.com/google/battery-historian">Battery Historian + on GitHub</a> + </li> + + <li> + <a href="https://developer.android.com/studio/profile/battery-historian.html"> + Batterystats and Battery Historian Walkthrough + </li> + + <li> + <a href="https://youtu.be/VC2Hlb22mZM?list=PLOU2XLYxmsILe6_eGvDN3GyiodoV3qNSC&t=2063" + target="_blank"> + Battery Historian talk at Google I/O 2016</a> + </li> + </ol> + </div> +</div> + +<p> +The Battery Historian tool provides insight into a device’s battery consumption +over time. At a system-wide level, the tool visualizes power-related events from +the system logs in an HTML representation. At an app-specific level, the tool +provides a variety of data that can help you identify battery-draining app +behavior. +</p> + +<p> +This document describes some of the ways you can use Battery Historian +to learn about battery-consumption patterns. The document begins by explaining +how to read the system-wide data that Battery Historian reports. Then, +it presents ways in which you can use Battery Historian to diagnose +and troubleshoot your own app's behavior related to battery consumption. +Last, it offers several tips on scenarios in which Battery Historian may be +particularly useful. +</p> + +<h2 id="sv">System-wide View</h2> + +<p> +The Battery Historian tool provides a system-wide visualization of various +app and system behaviors, along with their correlation against battery +consumption over time. This view, shown in Figure 1, can help you +diagnose and identify power use issues with your app. +</p> + + <img src="{@docRoot}topic/performance/images/generic-timeline.png"> + <p class="img-caption"> +<strong>Figure 1.</strong> +Battery Historian’s display of system-wide events affecting power +consumption. + </p> + +<p> +Of particular interest in this figure is the black, horizontal, downward trend +line representing Battery Level, measured on the y-axis. For example, at the +very beginning of the Battery Level line, at approximately 6:50 AM, the +visualization shows a relatively steep drop in battery level. +</p> + +<p> +Figure 2 provides a close-up of that part of the display. +</p> + + <img src="{@docRoot}topic/performance/images/s-generic-closeup.png"> + <p class="img-caption"> +<strong>Figure 2.</strong> +A close-up of the Battery Historian timeline from roughly 6:50 AM to 7:20 AM. + </p> + +<p> +At the very beginning of the Battery Level line, as battery decline steeply, +the display shows three things happening: The CPU is running, an app has +acquired a wakelock, and the screen is on. In this way, Battery Historian helps +you understand what events are happening when battery consumption is high. You +can then target these behaviors in your app and investigate whether there are +related optimizations you can make. +</p> + +<p> +The system-wide visualization can provide other clues, as well. For instance, if +it shows that the mobile radio is frequently being turned off and on, there may +be an opportunity to optimize this behavior through <a href=”intelligent +scheduling page”>intelligent scheduling APIs</a> such as JobScheduler or +Firebase Job Dispatcher. +</p> + +<p> +The next section explains how to investigate behavior and events specific to +your own app. +</p> + +<p> +<h2 id="asd">App-Specific Data</h2> +</p> + +<p> +In addition to the macro-level data provided by the system-wide view, Battery +Historian also provides tables and some visualization of data specific to each +app running on your device. The tabular data includes: +</p> + +<ul> + <li>The app’s estimated power use on the device.</li> + <li>Network information.</li> + <li>Wakelocks.</li> + <li>Services.</li> + <li>Process info.</li> +</ul> + +<p> +The tables provide two dimensions of data about your app. First, you can look +up where your app’s power usage ranks compared to other apps. To do so, click +<em>Device Power Estimates</em> table under <em>Tables</em>. This example +examines a fictional app called Pug Power. +</p> + + <img src="{@docRoot}topic/performance/images/app-rankings.png"> + <p class="img-caption"> +<strong>Figure 3.</strong> Investigating which apps consume the most power. + </p> + +<p> +The table in Figure 3 reveals that Pug Power is the ninth biggest consumer of +battery power on this device, and the third biggest app that is not part of the +OS. This data suggests that this app bears deeper investigation. +</p> + +<p> +To look up the data for a specific app, enter its package name into the lower +of the two dropdown menus under <em>App Selection</em>, located under the left +side of the visualization. +</p> + + <img src="{@docRoot}topic/performance/images/dropdown.png"> + <p class="img-caption"> +<strong>Figure 4.</strong> Entering a specific app whose data to view. + </p> + +<p> +When you select a specific app, the following data visualization categories +change to display app-specific data instead of system-wide data: +</p> + +<ul> + <li>SyncManager.</li> + <li>Foreground process.</li> + <li>Userspace Wakelock.</li> + <li>Top app.</li> + <li>JobScheduler.</li> + <li>Activity Manager Proc.</li> +</ul> + +The SyncManager and JobScheduler visualizations immediately make it obvious if +your app performs syncs and executes jobs more frequently than necessary. In +doing so, they can quickly reveal an opportunity to optimize your app’s +behavior for improved battery performance. + +<p> +You can also obtain one more piece of app-specific visualization data, +<em>Userspace Wakelock</em>. To include this information in the bug report, +enter the following command in your terminal window: +</p> + +<pre> +$ adb shell dumpsys batterystats --enable full-wake-history +</pre> + +<p class="note"> +<strong>Note:</strong> From Android 6.0 (API level 23), the platform includes +Doze functionality, which imposes certain optimizations on apps. For example, +Doze batches jobs to take place during brief maintenance windows, regardless of +how JobScheduler has scheduled them. +</p> + +<p> +Figures 5 and 6 show data for Pug Power: Figure 5 +shows the visualization of +the app-specific data, and Figure 6 shows the corresponding tabular data. +</p> + + <img src="{@docRoot}topic/performance/images/pug-visualization.png"> + <p class="img-caption"> +<strong>Figure 5.</strong> Visualization of data for fictional app Pug Power. + </p> + + <img src="{@docRoot}topic/performance/images/pugspecificdata.png"> + <p class="img-caption"> +<strong>Figure 6.</strong> Tabular data for the fictional Pug Power app. + </p> + +<p> +A look at the visualization does not show anything immediately obvious. +The JobScheduler line shows that the app has no jobs scheduled. The SyncManager +line shows that the app has not performed any syncs. +</p> + +<p> +However, examination of the <em>Wakelocks</em> segment of the tabular data +reveals that Pug Power acquires wakelocks totaling over an hour. This unusual +and costly behavior can account for the app’s high level of power consumption. +This piece of information helps the developer target an area where optimization +is likely to greatly help. In this case, why does the app acquire so much +wakelock time, and how can the developer ameliorate this behavior? +</p> + +<h2 id="usecases">Other Cases Where Battery Historian Can Help</h2> + +<p> +There are many other cases in which Battery Historian can help you diagnose +opportunities for improving battery behavior. For example, Battery Historian +can tell you if your app is: +</p> + +<ul> + <li>Firing wakeup alarms overly frequently (every 10 seconds or less).</li> + <li>Continuously holding a GPS lock.</li> + <li>Scheduling jobs every 30 seconds or less.</li> + <li>Scheduling syncs every 30 seconds or less.</li> + <li>Using the cellular radio more frequently than you expect.</li> +</ul> + diff --git a/docs/html/topic/performance/power/index.jd b/docs/html/topic/performance/power/index.jd new file mode 100644 index 000000000000..88addcea1f71 --- /dev/null +++ b/docs/html/topic/performance/power/index.jd @@ -0,0 +1,125 @@ +page.title=Optimizing for Battery Life +page.metaDescription=Learn how to help your app go easier on the battery. + +meta.tags="performance" +page.tags="performance" + +@jd:body + +<div id="qv-wrapper"> + <div id="qv"> + <h2> + In this document + </h2> + <ol> + <li> + <a href="#lazy">Lazy First</a> + </li> + <li> + <a href="#features">Platform Features</a> + </li> + <li> + <a href="#toolery">Tooling</a> + </li> + </ol> + </div> +</div> + +<p>Battery life is the single most important aspect of the mobile user +experience. A device without power offers no functionality at all. +For this reason, it is critically important that apps be as respectful of +battery life as possible.</p> + +<p>There are three important things to keep in mind in keeping your app +power-thrifty:</p> +<ul> +<li>Make your apps <em>Lazy First</em>.</li> +<li>Take advantage of platform features that can help manage your app's battery +consumption.</li> +<li>Use tools that can help you identify battery-draining culprits.</li> +</ul> + +<h2 id="lazy">Lazy First</h2> + +<p>Making your app Lazy First means looking for ways to reduce and optimize +operations that are particularly battery-intensive. The core questions +underpinning Lazy First design are: + +<ul> + + <li><strong>Reduce:</strong> Are there redundant operations your app can cut +out? For example, can it cache downloaded data instead of repeatedly waking + up the radio to re-download the data?</li> + + <li><strong>Defer:</strong> Does an app need to perform an action right + away? For example, + can it wait until the device is charging before it backs data up to the + cloud?</li> + + <li><strong>Coalesce:</strong> Can work be batched, instead of putting the + device + into an active state many times? For example, is it really necessary for + several dozen apps to each turn on the radio at separate times to send + their messages? Can the messages instead be transmitted during a + single awakening of the radio?</li> +</ul> + +<p> +You should ask these questions when it comes to using the CPU, +the radio, and the screen. Lazy First design is often a good way +to tame these battery killers. +</p> + +<p> +To help you achieve these and other efficiencies, the Android platform +provides a number of features to help maximize battery life. +</p> + +<h2 id="features">Platform Features</h2> + +<p> +Broadly speaking, the Android platform provides two categories of help +for you to optimize your app's battery use. First, it provides several +APIs that you can implement in your app. You can learn more about these APIs in +<a href="/topic/performance/scheduling.html">Intelligent Job Scheduling</a> +and <a href="/performance/power/network/index.html"> +Network Use and Battery Consumption</a>. +</p> + +<p> +There are also internal mechanisms in the platform to help conserve +battery life. While they are not APIs that you implement programmatically, +you should still be aware of them so that your app can leverage them +successfully. For more information, see +<a href="/training/monitoring-device-state/doze-standby.html">Doze and +App Standby</a>.</p> + +<p> +You can get even more benefit out of these features by using the tools +available for the platform to discover the parts of your app that consume +the most power. Finding what to target is a big step toward +successful optimization. +</p> + +<h2 id ="toolery">Tooling</h2> + +<p>There are tools for Android, including +<a href="/studio/profile/dev-options-rendering.html">Profile GPU Rendering</a> +and <a class="external-link" +href="https://github.com/google/battery-historian">Battery Historian</a> +to help you identify areas that you can optimize for better battery life. +Take advantage of these tools to target areas where you can apply the +principles of Lazy First. +</p> + +<section class="dac-section dac-small" id="latest-games"><div class="wrap"> + <h2 class="norule" style="margin:0 0">More resources</h2> + <div class="resource-widget resource-flow-layout col-16" + data-query="collection:develop/performance/landing" + data-sortOrder="random" + data-cardSizes="6x6" + data-maxResults="24" + data-items-per-page="24" + data-initial-results="3"></div> + </div> +</section> diff --git a/docs/html/topic/performance/rendering/index.jd b/docs/html/topic/performance/rendering/index.jd new file mode 100644 index 000000000000..1b16df035376 --- /dev/null +++ b/docs/html/topic/performance/rendering/index.jd @@ -0,0 +1,60 @@ +page.title=Rendering +page.article=true + +page.tags=battery +page.metaDescription=Learn how to optimize your app's rendering performance. + +@jd:body + + +<iframe width="448" height="252" + src="//www.youtube.com/embed/wIy8g8yNhNk?autohide=1&showinfo=0" + frameborder="0" allowfullscreen="" + style="float: right; margin: 0 0 20px 20px;"></iframe> + +<p> + A key aspect of your app that influences your users' perception of quality is + the smoothness with which it renders images and text to the screen. It is + important to avoid jank and sluggish responsiveness when your app is drawing + to the screen. +</p> + +<p> + This section helps you learn several ways to optimize your app's rendering + performance: reducing overdraw, optimizing view hierarchies, and taking + advantage of the Profile GPU tool. +</p> + +<h2>Rendering Actions</h2> + +<dl> + <dt> + <strong><a href="overdraw.html"> + Reducing Overdraw</a></strong> + </dt> + <dd> + Minimize the number of times you app redraws the same pixel in a single + frame. + </dd> + + <dt> + <strong><a href="optimizing-view-hierarchies.html"> + Performance and View Hierarchies</a></strong> + </dt> + <dd> + Make sure your layout and measurement are executing efficiently, and + avoid double taxation. + </dd> + + + <dt> + <strong><a href="profile-gpu.html"> + Analyzing with Profile GPU Rendering</a></strong> + </dt> + <dd> + Take advantage of this on-device tool to identify bottlenecks that + may be slowing your app's rendering down. + </dd> + + +</dl> diff --git a/docs/html/topic/performance/optimizing-view-hierarchies.jd b/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd index 27d3d163f853..27d3d163f853 100644 --- a/docs/html/topic/performance/optimizing-view-hierarchies.jd +++ b/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd diff --git a/docs/html/topic/performance/rendering/overdraw.jd b/docs/html/topic/performance/rendering/overdraw.jd new file mode 100644 index 000000000000..c1feff57a26b --- /dev/null +++ b/docs/html/topic/performance/rendering/overdraw.jd @@ -0,0 +1,197 @@ +page.title=Reducing Overdraw +page.metaDescription=Improve performance by reducing unnecessary rendering. + +meta.tags="performance" +page.tags="performance" + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> + <ol> + + <li> + <a href="#understanding">Understanding Overdraw</a> + </li> + <li> + <a href="#finding">Finding Overdraw Problems</a> + </li> + <li> + <a href="#fixing">Fixing Overdraw</a> + </li> + </ol> + </div> +</div> + +<p> +An app may draw the same pixel more than once within a single frame, an event +called <em>overdraw</em>. Overdraw is usually unnecessary, and best +eliminated. It manifests itself as a performance problem by wasting GPU time to +render pixels that don't contribute to what the user sees on the screen. +</p> + +<p> +This document explains overdraw: what it is, how to diagnose it, and actions you +can take to eliminate or mitigate it. +</p> + +<h2 name="understanding">Understanding Overdraw</h2> + +<p> +Overdraw refers to the system's drawing a pixel on the screen multiple times +in a single frame of rendering. For example, if we have a bunch of stacked UI +cards, each card hides a portion of the one below it. +</p> + +<p> +However, the system still needs to draw even the hidden portions of the cards +in the stack. This is because stacked cards are rendered according to the +<a class="external-link" +href="https://en.wikipedia.org/wiki/Painter%27s_algorithm">painter's +algorithm</a>: that is, in back-to-front order. +This sequence of rendering allows the system to apply proper alpha blending to +translucent objects such as shadows. +</p> + +<h2 name="finding">Finding Overdraw Problems</h2> + +<p> +The platform offers several tools to help you determine if overdraw is +affecting your app's performance. These tools are available right on the device, +and accessible by turning on <strong>Developer Settings</strong></a> under +<em>Settings</em>. For more information about device developer settings, see +<a href="/studio/run/device.html#developer-device-options">Run Apps on a +Hardware Device</a>. +</p> + +<h3 id="dgot">Debug GPU overdraw tool</h3> + +<p> +The Debug GPU Overdraw tool uses color-coding to show the number of times your +app draws each pixel on the screen. The higher this count, the +more likely it is that overdraw affects your app's performance. +</p> + +<p> +For more information on how to use the tool, refer to the related +<a href="/studio/profile/dev-options-overdraw.html">walkthrough</a> +and +<a href="https://io2015codelabs.appspot.com/codelabs/android-performance-debug-gpu-overdraw#1"> +codelab</a>. +</p> + +<h3 id="pgrt">Profile GPU rendering tool</h3> + +<p> +The Profile GPU Rendering tool displays, as a scrolling histogram, the time +each stage of the rendering pipeline takes to display a single frame. The +<em>Process</em> part of each bar, indicated in orange, shows when the system +is swapping buffers; this metric provides important clues about overdraw. +</p> + +<p> +On less performant GPUs, available fill-rate (the speed at which the GPU can +fill the frame buffer) can be quite low. As the number of +pixels required to draw a frame increases, the GPU may take longer to process +new commands, and ask the rest of the system to wait until it can catch up. +The <em>Process</em> bar shows that this spike happens as the GPU gets +overwhelmed trying to draw pixels as fast as possible. Issues other than +raw numbers of pixels may also cause this metric to spike. For example, +if the Debug GPU Overdraw tool shows heavy overdraw and <em>Process</em> spikes, +there's likely an issue with overdraw. +</p> + +<p class="note"><strong>Note: </strong>The +<a href="https://developer.android.com/studio/profile/dev-options-rendering.html"> +Profile GPU Rendering</a> tool does not +work with apps that use the NDK. This is because the system pushes framework +messages to the background whenever OpenGL takes a full-screen context. In +such cases, you may find a profiling tool provided by the GPU manufacturer +helpful.</p> + +<h2 name="fixing">Fixing Overdraw</h2> + +<p> +There are several strategies you can pursue to reduce or eliminate overdraw: +</p> + +<ul> + <li>Removing unneeded backgrounds in layouts.</li> + <li>Flattening the view hierarchy.</li> + <li>Reducing transparency.</li> +</ul> + +<p> +This section provides information about each of these approaches. +</p> + +<h3 id="rubil">Removing unneeded backgrounds in layouts</h3> + +<p> +By default, a layout does not have a background, which means it does not render +anything directly by itself. When layouts do have backgrounds, however, they may +contribute to overdraw. +</p> + +<p> +Removing unnecessary backgrounds is a quick way of improving rendering +performance. An unnecessary background may never be visible because it's +completely covered by everything else the app is drawing on top of that +view. For example, the system may entirely cover up a parent's +background when it draws child views on top of it. +</p> + +<p> +To find out why you're overdrawing, walk through the hierarchy in +the <a href="/studio/profile/hierarchy-viewer.html">Hierarchy Viewer</a> tool. +As you do so, look out for any backgrounds you can eliminate because +they are not visible to the user. Cases where many containers share a +common background color offer another opportunity to eliminate unneeded +backgrounds: You can set the window background to the main background color +of your app, and leave all of the containers above it with no background values +defined. +</p> + +<h3 id="fvh">Flattening view hierarchy</h3> + +<p> +Modern layouts make it easy to stack and layer views to produce beautiful +design. However, doing so can degrade performance by resulting in overdraw, +especially in scenarios where each stacked view object is opaque, requiring the +drawing of both seen and unseen pixels to the screen. +</p> + +<p> +If you encounter this sort of issue, you may be able to improve performance by +optimizing your view hierarchy to reduce the number of overlapping UI objects. +For more information about how to accomplish this, see +<a href="/topic/performance/optimizing-view-hierarchies.html">Optimizing View +Hierarchies</a>. +</p> + +<h3 id="rt">Reducing transparency</h3> + +<p> +Rendering of transparent pixels on screen, known as alpha rendering, is a key +contributor to overdraw. Unlike standard overdraw, +in which the system completely hides existing drawn pixels by drawing +opaque pixels on top of them, transparent +objects require existing pixels to be drawn first, so that the right blending +equation can occur. Visual effects like transparent animations, fade-outs, and +drop shadows all involve some sort of transparency, and can therefore contribute +significantly to overdraw. You can improve overdraw in these situations by +reducing the number of transparent objects you render. For example, you can get +gray text by drawing black text in a {@link android.widget.TextView} with a +translucent alpha value set on it. But you can get the same effect with far +better performance by simply drawing the text in gray. +</p> + +<p> +To learn more about performance costs that transparency imposes throughout the +entire drawing pipeline, watch the video +<a href="https://www.youtube.com/watch?v=wIy8g8yNhNk&index=46&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE"> +Hidden Costs of Transparency</a>. +</p> + diff --git a/docs/html/topic/performance/rendering/profile-gpu.jd b/docs/html/topic/performance/rendering/profile-gpu.jd new file mode 100644 index 000000000000..fc9877772610 --- /dev/null +++ b/docs/html/topic/performance/rendering/profile-gpu.jd @@ -0,0 +1,406 @@ +page.title=Analyzing with Profile GPU Rendering +page.metaDescription=Use the Profile GPU tool to help you optimize your app's rendering performance. + +meta.tags="power" +page.tags="power" + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> + <ol> + <li> + <a href="#visrep">Visual Representation</a></li> + </li> + + <li> + <a href="#sam">Stages and Their Meanings</a> + + <ul> + <li> + <a href="#sv">Input Handling</a> + </li> + <li> + <a href="#asd">Animation</a> + </li> + <li> + <a href="#asd">Measurement/Layout</a> + </li> + <li> + <a href="#asd">Drawing</a> + </li> + </li> + <li> + <a href="#asd">Sync/Upload</a> + </li> + <li> + <a href="#asd">Issuing Commands</a> + </li> + <li> + <a href="#asd">Processing/Swapping Buffer</a> + </li> + <li> + <a href="#asd">Miscellaneous</a> + </li> + </ul> + </li> + </ol> + </div> +</div> + +<p> +The <a href="/studio/profile/dev-options-rendering.html"> +Profile GPU Rendering</a> tool indicates the relative time that each stage of +the rendering pipeline takes to render the previous frame. This knowledge +can help you identify bottlenecks in the pipeline, so that you +can know what to optimize to improve your app's rendering performance. +</p> + +<p> +This page briefly explains what happens during each pipeline stage, and +discusses issues that can cause bottlenecks there. Before reading +this page, you should be familiar with the information presented in the +<a href="/studio/profile/dev-options-rendering.html">Profile GPU +Rendering Walkthrough</a>. In addition, to understand how all of the +stages fit together, it may be helpful to review +<a href="https://www.youtube.com/watch?v=we6poP0kw6E&index=64&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE"> +how the rendering pipeline works.</a> +</p> + +<h2 id="#visrep">Visual Representation</h2> + +<p> +The Profile GPU Rendering tool displays stages and their relative times in the +form of a graph: a color-coded histogram. Figure 1 shows an example of +such a display. +</p> + + <img src="{@docRoot}topic/performance/images/bars.png"> + <p class="img-caption"> +<strong>Figure 1.</strong> Profile GPU Rendering Graph + </p> + +</p> + +<p> +Each segment of each vertical bar displayed in the Profile GPU Rendering +graph represents a stage of the pipeline and is highlighted using a specific +color in +the bar graph. Figure 2 shows a key to the meaning of each displayed color. +</p> + + <img src="{@docRoot}topic/performance/images/s-profiler-legend.png"> + <p class="img-caption"> +<strong>Figure 2.</strong> Profile GPU Rendering Graph Legend + </p> + +<p> +Once you understand what each color signfiies, +you can target specific aspects of your +app to try to optimize its rendering performance. +</p> + +<h2 id="sam">Stages and Their Meanings</a></h2> + +<p> +This section explains what happens during each stage corresponding +to a color in Figure 2, as well as bottleneck causes to look out for. +</p> + + +<h3 id="ih">Input Handling</h3> + +<p> +The input handling stage of the pipeline measures how long the app +spent handling input events. This metric indicates how long the app +spent executing code called as a result of input event callbacks. +</p> + +<h4>When this segment is large</h4> + +<p> +High values in this area are typically a result of too much work, or +too-complex work, occurring inside the input-handler event callbacks. +Since these callbacks always occur on the main thread, solutions to this +problem focus on optimizing the work directly, or offloading the work to a +different thread. +</p> + +<p> +It’s also worth noting that {@link android.support.v7.widget.RecyclerView} +scrolling can appear in this phase. +{@link android.support.v7.widget.RecyclerView} scrolls immediately when it +consumes the touch event. As a result, +it can inflate or populate new item views. For this reason, it’s important to +make this operation as fast as possible. Profiling tools like Traceview or +Systrace can help you investigate further. +</p> + +<h3 id="at">Animation</h3> + +<p> +The Animations phase shows you just how long it took to evaluate all the +animators that were running in that frame. The most common animators are +{@link android.animation.ObjectAnimator}, +{@link android.view.ViewPropertyAnimator}, and +<a href="/training/transitions/overview.html">Transitions</a>. +</p> + +<h4>When this segment is large</h4> + +<p> +High values in this area are typically a result of work that’s executing due +to some property change of the animation. For example, a fling animation, +which scrolls your {@link android.widget.ListView} or +{@link android.support.v7.widget.RecyclerView}, causes large amounts of view +inflation and population. +</p> + +<h3 id="ml">Measurement/Layout</h3> + +<p> +In order for Android to draw your view items on the screen, it executes +two specific operations across layouts and views in your view hierarchy. +</p> + +<p> +First, the system measures the view items. Every view and layout has +specific data that describes the size of the object on the screen. Some views +can have a specific size; others have a size that adapts to the size +of the parent layout container +</p> + +<p> +Second, the system lays out the view items. Once the system calculates +the sizes of children views, the system can proceed with layout, sizing +and positioning the views on the screen. +</p> + +<p> +The system performs measurement and layout not only for the views to be drawn, +but also for the parent hierarchies of those views, all the way up to the root +view. +</p> + +<h4>When this segment is large</h4> + +<p> +If your app spends a lot of time per frame in this area, it is +usually either because of the sheer volume of views that need to be +laid out, or problems such as +<a href="/topic/performance/optimizing-view-hierarchies.html#double"> +double taxation</a> at the wrong spot in your +hierarchy. In either of these cases, addressing performance involves +<a href="/topic/performance/optimizing-view-hierarchies.html">improving +the performance of your view hierarchies</a>. +</p> + +<p> +Code that you’ve added to +{@link android.view.View#onLayout(boolean, int, int, int, int)} or +{@link android.view.View#onMeasure(int, int)} +can also cause performance +issues. <a href="/studio/profile/traceview.html">Traceview</a> and +<a href="/studio/profile/systrace.html">Systrace</a> can help you examine +the callstacks to identify problems your code may have. +</p> + +<h3 id="draw">Drawing</h3> + +<p> +The draw stage translates a view’s rendering operations, such as drawing +a background or drawing text, into a sequence of native drawing commands. +The system captures these commands into a display list. +</p> + +<p> +The Draw bar records how much time it takes to complete capturing the commands +into the display list, for all the views that needed to be updated on the screen +this frame. The measured time applies to any code that you have added to the UI +objects in your app. Examples of such code may be the +{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}, +{@link android.view.View#dispatchDraw(android.graphics.Canvas) dispatchDraw()}, +and the various <code>draw ()methods</code> belonging to the subclasses of the +{@link android.graphics.drawable.Drawable} class. +</p> + +<h4>When this segment is large</h4> + +<p> +In simplified terms, you can understand this metric as showing how long it took +to run all of the calls to +{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()} +for each invalidated view. This +measurement includes any time spent dispatching draw commands to children and +drawables that may be present. For this reason, when you see this bar spike, the +cause could be that a bunch of views suddenly became invalidated. Invalidation +makes it necessary to regenerate views' display lists. Alternatively, a +lengthy time may be the result of a few custom views that have some extremely +complex logic in their +{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()} methods. +</p> + +<h3 id="su">Sync/Upload</h3> + +<p> +The Sync & Upload metric represents the time it takes to transfer +bitmap objects from CPU memory to GPU memory during the current frame. +</p> + +<p> +As different processors, the CPU and the GPU have different RAM areas +dedicated to processing. When you draw a bitmap on Android, the system +transfers the bitmap to GPU memory before the GPU can render it to the +screen. Then, the GPU caches the bitmap so that the system doesn’t need to +transfer the data again unless the texture gets evicted from the GPU texture +cache. +</p> + +<p class="note"><strong>Note:</strong> On Lollipop devices, this stage is +purple. +</p> + +<h4>When this segment is large</h4> + +<p> +All resources for a frame need to reside in GPU memory before they can be +used to draw a frame. This means that a high value for this metric could mean +either a large number of small resource loads or a small number of very large +resources. A common case is when an app displays a single bitmap that’s +close to the size of the screen. Another case is when an app displays a +large number of thumbnails. +</p> + +<p> +To shrink this bar, you can employ techniques such as: +</p> + +<ul> + <li> +Ensuring your bitmap resolutions are not much larger than the size at which they +will be displayed. For example, your app should avoid displaying a 1024x1024 +image as a 48x48 image. + </li> + + <li> +Taking advantage of {@link android.graphics.Bitmap#prepareToDraw()} +to asynchronously pre-upload a bitmap before the next sync phase. + </li> +</ul> + +<h3 id="ic">Issuing Commands</h3> + +<p> +The <em>Issue Commands</em> segment represents the time it takes to issue all +of the commands necessary for drawing display lists to the screen. +</p> + +<p> +For the system to draw display lists to the screen, it sends the +necessary commands to the GPU. Typically, it performs this action through the +<a href="/guide/topics/graphics/opengl.html">OpenGL ES</a> API. +</p> + +<p> +This process takes some time, as the system performs final transformation +and clipping for each command before sending the command to the GPU. Additional +overhead then arises on the GPU side, which computes the final commands. These +commands include final transformations, and additional clipping. +</p> + +<h4>When this segment is large</h4> + +<p> +The time spent in this stage is a direct measure of the complexity and +quantity of display lists that the system renders in a given +frame. For example, having many draw operations, especially in cases where +there's a small inherent cost to each draw primitive, could inflate this time. +For example: +</p> + +<pre> +for (int i = 0; i < 1000; i++) +canvas.drawPoint() +</pre> + +<p> +is a lot more expensive to issue than: +</p> + +<pre> +canvas.drawPoints(mThousandPointArray); +</pre> + +<p> +There isn’t always a 1:1 correlation between issuing commands and +actually drawing display lists. Unlike <em>Issue Commands</em>, +which captures the time it takes to send drawing commands to the GPU, +the <em>Draw</em> metric represents the time that it took to capture the issued +commands into the display list. +</p> + +<p> +This difference arises because the display lists are cached by +the system wherever possible. As a result, there are situations where a +scroll, transform, or animation requires the system to re-send a display +list, but not have to actually rebuild it—recapture the drawing +commands—from scratch. As a result, you can see a high “Issue +commands” bar without seeing a high <em>Draw commands</em> bar. +</p> + +<h3 id="psb">Processing/Swapping Buffers</h3> + +<p> +Once Android finishes submitting all its display list to the GPU, +the system issues one final command to tell the graphics driver that it's +done with the current frame. At this point, the driver can finally present +the updated image to the screen. +</p> + +<h4>When this segment is large</h4> + +<p> +It’s important to understand that the GPU executes work in parallel with the +CPU. The Android system issues draw commands to the GPU, and then moves on to +the next task. The GPU reads those draw commands from a queue and processes +them. +</p> + +<p> +In situations where the CPU issues commands faster than the GPU +consumes them, the communications queue between the processors can become +full. When this occurs, the CPU blocks, and waits until there is space in the +queue to place the next command. This full-queue state arises often during the +<em>Swap Buffers</em> stage, because at that point, a whole frame’s worth of +commands have been submitted. +</p> + +</p> +The key to mitigating this problem is to reduce the complexity of work occurring +on the GPU, in similar fashion to what you would do for the “Issue Commands” +phase. +</p> + + +<h3 id="mt">Miscellaneous</h3> + +<p> +In addition to the time it takes the rendering system to perform its work, +there’s an additional set of work that occurs on the main thread and has +nothing to do with rendering. Time that this work consumes is reported as +<em>misc time</em>. Misc time generally represents work that might be occurring +on the UI thread between two consecutive frames of rendering. +</p> + +<h4>When this segment is large</h4> + +<p> +If this value is high, it is likely that your app has callbacks, intents, or +other work that should be happening on another thread. Tools such as +<a href="/studio/profile/traceview.html">Method +Tracing</a> or <a href="/studio/profile/systrace.html">Systrace</a> can provide +visibility into the tasks that are running on +the main thread. This information can help you target performance improvements. +</p> diff --git a/docs/html/training/_book.yaml b/docs/html/training/_book.yaml index e9635be74ec3..47862e240254 100644 --- a/docs/html/training/_book.yaml +++ b/docs/html/training/_book.yaml @@ -438,16 +438,6 @@ toc: path: /training/efficient-downloads/redundant_redundant.html - title: Modifying Patterns Based on the Connectivity Type path: /training/efficient-downloads/connectivity_patterns.html - - title: Backing up App Data to the Cloud - path: /training/backup/index.html - path_attributes: - - name: description - value: How to sync and back up app and user data to remote web services in the cloud and how to restore the data back to multiple devices. - section: - - title: Configuring Auto Backup - path: /training/backup/autosyncapi.html - - title: Using the Backup API - path: /training/backup/backupapi.html - title: Resolving Cloud Save Conflicts path: /training/cloudsave/conflict-res.html path_attributes: @@ -1156,7 +1146,7 @@ toc: value: 维护兼容性 - name: zh-tw-lang value: 維持相容性 - - title: Selecting Colors with the Palette API + - title: Selecting Colors with the Palette API path: /training/material/palette-colors.html - title: Best Practices for User Input @@ -1242,15 +1232,9 @@ toc: path: /training/scheduling/wakelock.html - title: Scheduling Repeating Alarms path: /training/scheduling/alarms.html - - title: Best Practices for Performance path: /training/best-performance.html section: - - title: Managing Your App's Memory - path: /training/articles/memory.html - path_attributes: - - name: description - value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices. - title: Performance Tips path: /training/articles/perf-tips.html path_attributes: @@ -1282,23 +1266,6 @@ toc: - name: description value: How to minimize the amount of power your app requires by adapting to current power conditions and performing power-hungry tasks at proper intervals. section: - - title: Reducing Network Battery Drain - path: /training/performance/battery/network/index.html - section: - - title: Collecting Network Traffic Data - path: /training/performance/battery/network/gather-data.html - - title: Analyzing Network Traffic Data - path: /training/performance/battery/network/analyze-data.html - - title: Optimizing User-Initiated Network Use - path: /training/performance/battery/network/action-user-traffic.html - - title: Optimizing App-Initiated Network Use - path: /training/performance/battery/network/action-app-traffic.html - - title: Optimizing Server-Initiated Network Use - path: /training/performance/battery/network/action-server-traffic.html - - title: Optimizing General Network Use - path: /training/performance/battery/network/action-any-traffic.html - - title: Optimizing for Doze and App Standby - path: /training/monitoring-device-state/doze-standby.html - title: Monitoring the Battery Level and Charging State path: /training/monitoring-device-state/battery-monitoring.html path_attributes: diff --git a/docs/html/training/articles/memory.jd b/docs/html/training/articles/memory.jd deleted file mode 100644 index de7af589aefd..000000000000 --- a/docs/html/training/articles/memory.jd +++ /dev/null @@ -1,740 +0,0 @@ -page.title=Managing Your App's Memory -page.tags=ram,low memory,OutOfMemoryError,onTrimMemory -page.article=true -@jd:body - - -<div id="tb-wrapper"> -<div id="tb"> - -<h2>In this document</h2> -<ol class="nolist"> - <li><a href="#Android">How Android Manages Memory</a> - <ol> - <li><a href="#SharingRAM">Sharing Memory</a></li> - <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li> - <li><a href="#RestrictingMemory">Restricting App Memory</a></li> - <li><a href="#SwitchingApps">Switching Apps</a></li> - </ol> - </li> - <li><a href="#YourApp">How Your App Should Manage Memory</a> - <ol> - <li><a href="#Services">Use services sparingly</a></li> - <li><a href="#ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</a></li> - <li><a href="#ReleaseMemoryAsTight">Release memory as memory becomes tight</a></li> - <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li> - <li><a href="#Bitmaps">Avoid wasting memory with bitmaps</a></li> - <li><a href="#DataContainers">Use optimized data containers</a></li> - <li><a href="#Overhead">Be aware of memory overhead</a></li> - <li><a href="#Abstractions">Be careful with code abstractions</a></li> - <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li> - <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li> - <li><a href="#ExternalLibs">Be careful about using external libraries</a></li> - <li><a href="#OverallPerf">Optimize overall performance</a></li> - <li><a href="#Proguard">Use ProGuard to strip out any unneeded code</a></li> - <li><a href="#Zipalign">Use zipalign on your final APK</a></li> - <li><a href="#AnalyzeRam">Analyze your RAM usage</a></li> - <li><a href="#MultipleProcesses">Use multiple processes</a></li> - </ol> - </li> -</ol> -<h2>See Also</h2> -<ul> - <li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a> - </li> -</ul> - -</div> -</div> - - -<p>Random-access memory (RAM) is a valuable resource in any software development environment, but -it's even more valuable on a mobile operating system where physical memory is often constrained. -Although Android's Dalvik virtual machine performs routine garbage collection, this doesn't allow -you to ignore when and where your app allocates and releases memory.</p> - -<p>In order for the garbage collector to reclaim memory from your app, you need to avoid -introducing memory leaks (usually caused by holding onto object references in global members) and -release any {@link java.lang.ref.Reference} objects at the appropriate time (as defined by -lifecycle callbacks discussed further below). For most apps, the Dalvik garbage collector takes -care of the rest: the system reclaims your memory allocations when the corresponding objects leave -the scope of your app's active threads.</p> - -<p>This document explains how Android manages app processes and memory allocation, and how you can -proactively reduce memory usage while developing for Android. For more information about general -practices to clean up your resources when programming in Java, refer to other books or online -documentation about managing resource references. If you’re looking for information about how to -analyze your app’s memory once you’ve already built it, read <a -href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p> - - - - -<h2 id="Android">How Android Manages Memory</h2> - -<p>Android does not offer swap space for memory, but it does use <a href= -"http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a> and <a href= -"http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a> -(mmapping) to manage memory. This means that any memory you modify—whether by allocating -new objects or touching mmapped pages—remains resident in RAM and cannot be paged out. -So the only way to completely release memory from your app is to release object references you may -be holding, making the memory available to the garbage collector. That is with one exception: -any files mmapped in without modification, such as code, can be paged out of RAM if the system -wants to use that memory elsewhere.</p> - - -<h3 id="SharingRAM">Sharing Memory</h3> - -<p>In order to fit everything it needs in RAM, Android tries to share RAM pages across processes. It -can do so in the following ways:</p> -<ul> -<li>Each app process is forked from an existing process called Zygote. -The Zygote process starts when the system boots and loads common framework code and resources -(such as activity themes). To start a new app process, the system forks the Zygote process then -loads and runs the app's code in the new process. This allows most of the RAM pages allocated for -framework code and resources to be shared across all app processes.</li> - -<li>Most static data is mmapped into a process. This not only allows that same data to be shared -between processes but also allows it to be paged out when needed. Example static data include: -Dalvik code (by placing it in a pre-linked {@code .odex} file for direct mmapping), app resources -(by designing the resource table to be a structure that can be mmapped and by aligning the zip -entries of the APK), and traditional project elements like native code in {@code .so} files.</li> - -<li>In many places, Android shares the same dynamic RAM across processes using explicitly allocated -shared memory regions (either with ashmem or gralloc). For example, window surfaces use shared -memory between the app and screen compositor, and cursor buffers use shared memory between the -content provider and client.</li> -</ul> - -<p>Due to the extensive use of shared memory, determining how much memory your app is using requires -care. Techniques to properly determine your app's memory use are discussed in <a -href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p> - - -<h3 id="AllocatingRAM">Allocating and Reclaiming App Memory</h3> - -<p>Here are some facts about how Android allocates then reclaims memory from your app:</p> - -<ul> -<li>The Dalvik heap for each process is constrained to a single virtual memory range. This defines -the logical heap size, which can grow as it needs to (but only up to a limit that the system defines -for each app).</li> - -<li>The logical size of the heap is not the same as the amount of physical memory used by the heap. -When inspecting your app's heap, Android computes a value called the Proportional Set Size (PSS), -which accounts for both dirty and clean pages that are shared with other processes—but only in an -amount that's proportional to how many apps share that RAM. This (PSS) total is what the system -considers to be your physical memory footprint. For more information about PSS, see the <a -href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating Your -RAM Usage</a> guide.</li> - -<li>The Dalvik heap does not compact the logical size of the heap, meaning that Android does not -defragment the heap to close up space. Android can only shrink the logical heap size when there -is unused space at the end of the heap. But this doesn't mean the physical memory used by the heap -can't shrink. After garbage collection, Dalvik walks the heap and finds unused pages, then returns -those pages to the kernel using madvise. So, paired allocations and deallocations of large -chunks should result in reclaiming all (or nearly all) the physical memory used. However, -reclaiming memory from small allocations can be much less efficient because the page used -for a small allocation may still be shared with something else that has not yet been freed.</li> -</ul> - - -<h3 id="RestrictingMemory">Restricting App Memory</h3> - -<p>To maintain a functional multi-tasking environment, Android sets a hard limit on the heap size -for each app. The exact heap size limit varies between devices based on how much RAM the device -has available overall. If your app has reached the heap capacity and tries to allocate more -memory, it will receive an {@link java.lang.OutOfMemoryError}.</p> - -<p>In some cases, you might want to query the system to determine exactly how much heap space you -have available on the current device—for example, to determine how much data is safe to keep in a -cache. You can query the system for this figure by calling {@link -android.app.ActivityManager#getMemoryClass()}. This returns an integer indicating the number of -megabytes available for your app's heap. This is discussed further below, under -<a href="#CheckHowMuchMemory">Check how much memory you should use</a>.</p> - - -<h3 id="SwitchingApps">Switching Apps</h3> - -<p>Instead of using swap space when the user switches between apps, Android keeps processes that -are not hosting a foreground ("user visible") app component in a least-recently used (LRU) cache. -For example, when the user first launches an app, a process is created for it, but when the user -leaves the app, that process does <em>not</em> quit. The system keeps the process cached, so if -the user later returns to the app, the process is reused for faster app switching.</p> - -<p>If your app has a cached process and it retains memory that it currently does not need, -then your app—even while the user is not using it—is constraining the system's -overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache -beginning with the process least recently used, but also giving some consideration toward -which processes are most memory intensive. To keep your process cached as long as possible, follow -the advice in the following sections about when to release your references.</p> - -<p>More information about how processes are cached while not running in the foreground and how -Android decides which ones -can be killed is available in the <a href="{@docRoot}guide/components/processes-and-threads.html" ->Processes and Threads</a> guide.</p> - - - - -<h2 id="YourApp">How Your App Should Manage Memory</h2> - -<p>You should consider RAM constraints throughout all phases of development, including during app -design (before you begin development). There are many -ways you can design and write code that lead to more efficient results, through aggregation of the -same techniques applied over and over.</p> - -<p>You should apply the following techniques while designing and implementing your app to make it -more memory efficient.</p> - - -<h3 id="Services">Use services sparingly</h3> - -<p>If your app needs a <a href="{@docRoot}guide/components/services.html">service</a> -to perform work in the background, do not keep it running unless -it's actively performing a job. Also be careful to never leak your service by failing to stop it -when its work is done.</p> - -<p>When you start a service, the system prefers to always keep the process for that service -running. This makes the process very expensive because the RAM used by the service can’t be used by -anything else or paged out. This reduces the number of cached processes that the system can keep in -the LRU cache, making app switching less efficient. It can even lead to thrashing in the system -when memory is tight and the system can’t maintain enough processes to host all the services -currently running.</p> - -<p>The best way to limit the lifespan of your service is to use an {@link -android.app.IntentService}, which finishes -itself as soon as it's done handling the intent that started it. For more information, read -<a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a> -.</p> - -<p>Leaving a service running when it’s not needed is <strong>one of the worst memory-management -mistakes</strong> an Android app can make. So don’t be greedy by keeping a service for your app -running. Not only will it increase the risk of your app performing poorly due to RAM constraints, -but users will discover such misbehaving apps and uninstall them.</p> - - -<h3 id="ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</h3> - -<p>When the user navigates to a different app and your UI is no longer visible, you should -release any resources that are used by only your UI. Releasing UI resources at this time can -significantly increase the system's capacity for cached processes, which has a direct impact on the -quality of the user experience.</p> - -<p>To be notified when the user exits your UI, implement the {@link -android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback in your {@link -android.app.Activity} classes. You should use this -method to listen for the {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} level, -which indicates your UI is now hidden from view and you should free resources that only your UI -uses.</p> - - -<p>Notice that your app receives the {@link android.content.ComponentCallbacks2#onTrimMemory -onTrimMemory()} callback with {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} -only when <em>all the UI components</em> of your app process become hidden from the user. -This is distinct -from the {@link android.app.Activity#onStop onStop()} callback, which is called when an {@link -android.app.Activity} instance becomes hidden, which occurs even when the user moves to -another activity in your app. So although you should implement {@link android.app.Activity#onStop -onStop()} to release activity resources such as a network connection or to unregister broadcast -receivers, you usually should not release your UI resources until you receive {@link -android.content.ComponentCallbacks2#onTrimMemory onTrimMemory(TRIM_MEMORY_UI_HIDDEN)}. This ensures -that if the user navigates <em>back</em> from another activity in your app, your UI resources are -still available to resume the activity quickly.</p> - - - -<h3 id="ReleaseMemoryAsTight">Release memory as memory becomes tight</h3> - -<p>During any stage of your app's lifecycle, the {@link -android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback also tells you when -the overall device memory is getting low. You should respond by further releasing resources based -on the following memory levels delivered by {@link android.content.ComponentCallbacks2#onTrimMemory -onTrimMemory()}:</p> - -<ul> -<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_MODERATE} -<p>Your app is running and not considered killable, but the device is running low on memory and the -system is actively killing processes in the LRU cache.</p> -</li> - -<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_LOW} -<p>Your app is running and not considered killable, but the device is running much lower on -memory so you should release unused resources to improve system performance (which directly -impacts your app's performance).</p> -</li> - -<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_CRITICAL} -<p>Your app is still running, but the system has already killed most of the processes in the -LRU cache, so you should release all non-critical resources now. If the system cannot reclaim -sufficient amounts of RAM, it will clear all of the LRU cache and begin killing processes that -the system prefers to keep alive, such as those hosting a running service.</p> -</li> -</ul> - -<p>Also, when your app process is currently cached, you may receive one of the following -levels from {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}:</p> -<ul> -<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_BACKGROUND} -<p>The system is running low on memory and your process is near the beginning of the LRU list. -Although your app process is not at a high risk of being killed, the system may already be killing -processes in the LRU cache. You should release resources that are easy to recover so your process -will remain in the list and resume quickly when the user returns to your app.</p> -</li> - -<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_MODERATE} -<p>The system is running low on memory and your process is near the middle of the LRU list. If the -system becomes further constrained for memory, there's a chance your process will be killed.</p> -</li> - -<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} -<p>The system is running low on memory and your process is one of the first to be killed if the -system does not recover memory now. You should release everything that's not critical to -resuming your app state.</p> - -</li> -</ul> - -<p>Because the {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback was -added in API level 14, you can use the {@link android.content.ComponentCallbacks#onLowMemory()} -callback as a fallback for older versions, which is roughly equivalent to the {@link -android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.</p> - -<p class="note"><strong>Note:</strong> When the system begins killing processes in the LRU cache, -although it primarily works bottom-up, it does give some consideration to which processes are -consuming more memory and will thus provide the system more memory gain if killed. -So the less memory you consume while in the LRU list overall, the better your chances are -to remain in the list and be able to quickly resume.</p> - - - -<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3> - -<p>As mentioned earlier, each Android-powered device has a different amount of RAM available to the -system and thus provides a different heap limit for each app. You can call {@link -android.app.ActivityManager#getMemoryClass()} to get an estimate of your app's available heap in -megabytes. If your app tries to allocate more memory than is available here, it will receive an -{@link java.lang.OutOfMemoryError}.</p> - -<p>In very special situations, you can request a larger heap size by setting the <a -href="{@docRoot}guide/topics/manifest/application-element.html#largeHeap">{@code largeHeap}</a> -attribute to "true" in the manifest <a -href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> -tag. If you do so, you can call {@link -android.app.ActivityManager#getLargeMemoryClass()} to get an estimate of the large heap size.</p> - -<p>However, the ability to request a large heap is intended only for a small set of apps that can -justify the need to consume more RAM (such as a large photo editing app). <strong>Never request a -large heap simply because you've run out of memory</strong> and you need a quick fix—you -should use it only when you know exactly where all your memory is being allocated and why it must -be retained. Yet, even when you're confident your app can justify the large heap, you should avoid -requesting it to whatever extent possible. Using the extra memory will increasingly be to the -detriment of the overall user experience because garbage collection will take longer and system -performance may be slower when task switching or performing other common operations.</p> - -<p>Additionally, the large heap size is not the same on all devices and, when running on -devices that have limited RAM, the large heap size may be exactly the same as the regular heap -size. So even if you do request the large heap size, you should call {@link -android.app.ActivityManager#getMemoryClass()} to check the regular heap size and strive to always -stay below that limit.</p> - - -<h3 id="Bitmaps">Avoid wasting memory with bitmaps</h3> - -<p>When you load a bitmap, keep it in RAM only at the resolution you need for the current device's -screen, scaling it down if the original bitmap is a higher resolution. Keep in mind that an -increase in bitmap resolution results in a corresponding (increase<sup>2</sup>) in memory needed, -because both the X and Y dimensions increase.</p> - -<p class="note"><strong>Note:</strong> On Android 2.3.x (API level 10) and below, bitmap objects -always appear as the same size in your app heap regardless of the image resolution (the actual -pixel data is stored separately in native memory). This makes it more difficult to debug the bitmap -memory allocation because most heap analysis tools do not see the native allocation. However, -beginning in Android 3.0 (API level 11), the bitmap pixel data is allocated in your app's Dalvik -heap, improving garbage collection and debuggability. So if your app uses bitmaps and you're having -trouble discovering why your app is using some memory on an older device, switch to a device -running Android 3.0 or higher to debug it.</p> - -<p>For more tips about working with bitmaps, read <a -href="{@docRoot}training/displaying-bitmaps/manage-memory.html">Managing Bitmap Memory</a>.</p> - - -<h3 id="DataContainers">Use optimized data containers</h3> - -<p>Take advantage of optimized containers in the Android framework, such as {@link -android.util.SparseArray}, {@link android.util.SparseBooleanArray}, and {@link -android.support.v4.util.LongSparseArray}. The generic {@link java.util.HashMap} -implementation can be quite memory -inefficient because it needs a separate entry object for every mapping. Additionally, the {@link -android.util.SparseArray} classes are more efficient because they avoid the system's need -to <acronym title= -"Automatic conversion from primitive types to object classes (such as int to Integer)" ->autobox</acronym> -the key and sometimes value (which creates yet another object or two per entry). And don't be -afraid of dropping down to raw arrays when that makes sense.</p> - - - -<h3 id="Overhead">Be aware of memory overhead</h3> - -<p>Be knowledgeable about the cost and overhead of the language and libraries you are using, and -keep this information in mind when you design your app, from start to finish. Often, things on the -surface that look innocuous may in fact have a large amount of overhead. Examples include:</p> -<ul> -<li>Enums often require more than twice as much memory as static constants. You should strictly -avoid using enums on Android.</li> - -<li>Every class in Java (including anonymous inner classes) uses about 500 bytes of code.</li> - -<li>Every class instance has 12-16 bytes of RAM overhead.</li> - -<li>Putting a single entry into a {@link java.util.HashMap} requires the allocation of an -additional entry object that takes 32 bytes (see the previous section about <a -href="#DataContainers">optimized data containers</a>).</li> -</ul> - -<p>A few bytes here and there quickly add up—app designs that are class- or object-heavy will suffer -from this overhead. That can leave you in the difficult position of looking at a heap analysis and -realizing your problem is a lot of small objects using up your RAM.</p> - - -<h3 id="Abstractions">Be careful with code abstractions</h3> - -<p>Often, developers use abstractions simply as a "good programming practice," because abstractions -can improve code flexibility and maintenance. However, abstractions come at a significant cost: -generally they require a fair amount more code that needs to be executed, requiring more time and -more RAM for that code to be mapped into memory. So if your abstractions aren't supplying a -significant benefit, you should avoid them.</p> - - -<h3 id="NanoProto">Use nano protobufs for serialized data</h3> - -<p><a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol -buffers</a> are a language-neutral, platform-neutral, extensible mechanism designed by Google for -serializing structured data—think XML, but smaller, faster, and simpler. If you decide to use -protobufs for your data, you should always use nano protobufs in your client-side code. Regular -protobufs generate extremely verbose code, which will cause many kinds of problems in your app: -increased RAM use, significant APK size increase, slower execution, and quickly hitting the DEX -symbol limit.</p> - -<p>For more information, see the "Nano version" section in the <a -href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt" -class="external-link">protobuf readme</a>.</p> - - - -<h3 id="DependencyInjection">Avoid dependency injection frameworks</h3> - -<p>Using a dependency injection framework such as <a -href="https://code.google.com/p/google-guice/" class="external-link">Guice</a> or -<a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a> may be -attractive because they can simplify the code you write and provide an adaptive environment -that's useful for testing and other configuration changes. However, these frameworks tend to perform -a lot of process initialization by scanning your code for annotations, which can require significant -amounts of your code to be mapped into RAM even though you don't need it. These mapped pages are -allocated into clean memory so Android can drop them, but that won't happen until the pages have -been left in memory for a long period of time.</p> - - -<h3 id="ExternalLibs">Be careful about using external libraries</h3> - -<p>External library code is often not written for mobile environments and can be inefficient when used -for work on a mobile client. At the very least, when you decide to use an external library, you -should assume you are taking on a significant porting and maintenance burden to optimize the -library for mobile. Plan for that work up-front and analyze the library in terms of code size and -RAM footprint before deciding to use it at all.</p> - -<p>Even libraries supposedly designed for use on Android are potentially dangerous because each -library may do things differently. For example, one library may use nano protobufs while another -uses micro protobufs. Now you have two different protobuf implementations in your app. This can and -will also happen with different implementations of logging, analytics, image loading frameworks, -caching, and all kinds of other things you don't expect. <a -href="{@docRoot}tools/help/proguard.html">ProGuard</a> won't save you here because these -will all be lower-level dependencies that are required by the features for which you want the -library. This becomes especially problematic when you use an {@link android.app.Activity} -subclass from a library (which -will tend to have wide swaths of dependencies), when libraries use reflection (which is common and -means you need to spend a lot of time manually tweaking ProGuard to get it to work), and so on.</p> - -<p>Also be careful not to fall into the trap of using a shared library for one or two features out of -dozens of other things it does; you don't want to pull in a large amount of code and overhead that -you don't even use. At the end of the day, if there isn't an existing implementation that is a -strong match for what you need to do, it may be best if you create your own implementation.</p> - - -<h3 id="OverallPerf">Optimize overall performance</h3> - -<p>A variety of information about optimizing your app's overall performance is available -in other documents listed in <a href="{@docRoot}training/best-performance.html">Best Practices -for Performance</a>. Many of these documents include optimizations tips for CPU performance, but -many of these tips also help optimize your app's memory use, such as by reducing the number of -layout objects required by your UI.</p> - -<p>You should also read about <a href="{@docRoot}tools/debugging/debugging-ui.html">optimizing -your UI</a> with the layout debugging tools and take advantage of -the optimization suggestions provided by the <a -href="{@docRoot}tools/debugging/improving-w-lint.html">lint tool</a>.</p> - - -<h3 id="Proguard">Use ProGuard to strip out any unneeded code</h3> - -<p>The <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> tool shrinks, -optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and -methods with semantically obscure names. Using ProGuard can make your code more compact, requiring -fewer RAM pages to be mapped.</p> - - -<h3 id="Zipalign">Use zipalign on your final APK</h3> - -<p>If you do any post-processing of an APK generated by a build system (including signing it -with your final production certificate), then you must run <a -href="{@docRoot}tools/help/zipalign.html">zipalign</a> on it to have it re-aligned. -Failing to do so can cause your app to require significantly more RAM, because things like -resources can no longer be mmapped from the APK.</p> - -<p class="note"><strong>Note:</strong> Google Play Store does not accept APK files that -are not zipaligned.</p> - - -<h3 id="AnalyzeRam">Analyze your RAM usage</h3> - -<p>Once you achieve a relatively stable build, begin analyzing how much RAM your app is using -throughout all stages of its lifecycle. For information about how to analyze your app, read <a -href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p> - - - - -<h3 id="MultipleProcesses">Use multiple processes</h3> - -<p>If it's appropriate for your app, an advanced technique that may help you manage your app's -memory is dividing components of your app into multiple processes. This technique must always be -used carefully and <strong>most apps should not run multiple processes</strong>, as it can easily -increase—rather than decrease—your RAM footprint if done incorrectly. It is primarily -useful to apps that may run significant work in the background as well as the foreground and can -manage those operations separately.</p> - - -<p>An example of when multiple processes may be appropriate is when building a music player that -plays music from a service for long period of time. If -the entire app runs in one process, then many of the allocations performed for its activity UI must -be kept around as long as it is playing music, even if the user is currently in another app and the -service is controlling the playback. An app like this may be split into two process: one for its -UI, and the other for the work that continues running in the background service.</p> - -<p>You can specify a separate process for each app component by declaring the <a href= -"{@docRoot}guide/topics/manifest/service-element.html#proc">{@code android:process}</a> attribute -for each component in the manifest file. For example, you can specify that your service should run -in a process separate from your app's main process by declaring a new process named "background" -(but you can name the process anything you like):</p> - -<pre> -<service android:name=".PlaybackService" - android:process=":background" /> -</pre> - -<p>Your process name should begin with a colon (':') to ensure that the process remains private to -your app.</p> - -<p>Before you decide to create a new process, you need to understand the memory implications. -To illustrate the consequences of each process, consider that an empty process doing basically -nothing has an extra memory footprint of about 1.4MB, as shown by the memory information -dump below.</p> - -<pre class="no-pretty-print"> -adb shell dumpsys meminfo com.example.android.apis:empty - -** MEMINFO in pid 10172 [com.example.android.apis:empty] ** - Pss Pss Shared Private Shared Private Heap Heap Heap - Total Clean Dirty Dirty Clean Clean Size Alloc Free - ------ ------ ------ ------ ------ ------ ------ ------ ------ - Native Heap 0 0 0 0 0 0 1864 1800 63 - Dalvik Heap 764 0 5228 316 0 0 5584 5499 85 - Dalvik Other 619 0 3784 448 0 0 - Stack 28 0 8 28 0 0 - Other dev 4 0 12 0 0 4 - .so mmap 287 0 2840 212 972 0 - .apk mmap 54 0 0 0 136 0 - .dex mmap 250 148 0 0 3704 148 - Other mmap 8 0 8 8 20 0 - Unknown 403 0 600 380 0 0 - TOTAL 2417 148 12480 1392 4832 152 7448 7299 148 -</pre> - -<p class="note"><strong>Note:</strong> More information about how to read this output is provided -in <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating -Your RAM Usage</a>. The key data here is the <em>Private Dirty</em> and <em>Private -Clean</em> memory, which shows that this process is using almost 1.4MB of non-pageable RAM -(distributed across the Dalvik heap, native allocations, book-keeping, and library-loading), -and another 150K of RAM for code that has been mapped in to execute.</p> - -<p>This memory footprint for an empty process is fairly significant and it can quickly -grow as you start doing work in that process. For -example, here is the memory use of a process that is created only to show an activity with some -text in it:</p> - -<pre class="no-pretty-print"> -** MEMINFO in pid 10226 [com.example.android.helloactivity] ** - Pss Pss Shared Private Shared Private Heap Heap Heap - Total Clean Dirty Dirty Clean Clean Size Alloc Free - ------ ------ ------ ------ ------ ------ ------ ------ ------ - Native Heap 0 0 0 0 0 0 3000 2951 48 - Dalvik Heap 1074 0 4928 776 0 0 5744 5658 86 - Dalvik Other 802 0 3612 664 0 0 - Stack 28 0 8 28 0 0 - Ashmem 6 0 16 0 0 0 - Other dev 108 0 24 104 0 4 - .so mmap 2166 0 2824 1828 3756 0 - .apk mmap 48 0 0 0 632 0 - .ttf mmap 3 0 0 0 24 0 - .dex mmap 292 4 0 0 5672 4 - Other mmap 10 0 8 8 68 0 - Unknown 632 0 412 624 0 0 - TOTAL 5169 4 11832 4032 10152 8 8744 8609 134 -</pre> - -<p>The process has now almost tripled in size, to 4MB, simply by showing some text in the UI. This -leads to an important conclusion: If you are going to split your app into multiple processes, only -one process should be responsible for UI. Other processes should avoid any UI, as this will quickly -increase the RAM required by the process (especially once you start loading bitmap assets and other -resources). It may then be hard or impossible to reduce the memory usage once the UI is drawn.</p> - -<p>Additionally, when running more than one process, it's more important than ever that you keep your -code as lean as possible, because any unnecessary RAM overhead for common implementations are now -replicated in each process. For example, if you are using enums (though <a -href="#Overhead">you should not use enums</a>), all of -the RAM needed to create and initialize those constants is duplicated in each process, and any -abstractions you have with adapters and temporaries or other overhead will likewise be replicated.</p> - -<p>Another concern with multiple processes is the dependencies that exist between them. For example, -if your app has a content provider that you have running in the default process which also hosts -your UI, then code in a background process that uses that content provider will also require that -your UI process remain in RAM. If your goal is to have a background process that can run -independently of a heavy-weight UI process, it can't have dependencies on content providers or -services that execute in the UI process.</p> - - - - - - - - - - -<!-- THE FOLLOWING IS OVERWHELMING AND NOT NECESSARY FOR MOST APPS, LEAVING OUT FOR NOW - - -<p>You can examine the dependencies between your processes with the command:</p> - -<pre class="no-pretty-print"> -adb shell dumpsys activity -</pre> - -<p>This dumps various information about the Activity Manager's state, ending with a list of all -processes in their memory management order, including the reason each process is at its given -level. For example, below is a dump with the Music app in the foreground.</p> - -<pre class="no-pretty-print"> -ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes) - Process LRU list (sorted by oom_adj): - PERS # 4: adj=sys /F trm= 0 20674:system/1000 (fixed) - PERS #39: adj=pers /F trm= 0 20964:com.android.nfc/1027 (fixed) - PERS # 2: adj=pers /F trm= 0 20959:com.android.phone/1001 (fixed) - PERS # 1: adj=pers /F trm= 0 20779:com.android.systemui/u0a10057 (fixed) - Proc #11: adj=fore /FA trm= 0 8663:com.google.android.music:ui/u0a10043 (top-activity) - Proc #10: adj=fore /F trm= 0 30881:com.google.android.music:main/u0a10043 (provider) - com.google.android.music/.store.MusicContentProvider<=Proc{8663:com.google.android.music:ui/u0a10043} - Proc # 6: adj=fore /F trm= 0 21014:com.google.process.gapps/u0a10023 (provider) - com.google.android.gsf/.settings.GoogleSettingsProvider<=Proc{20935:com.google.process.location/u0a10023} - Proc #38: adj=vis /F trm= 0 21028:com.android.nfc:handover/1027 (service) - com.android.nfc/.handover.HandoverService<=Proc{20964:com.android.nfc/1027} - Proc # 7: adj=vis /B trm= 0 20935:com.google.process.location/u0a10023 (service) - com.google.android.location/.GeocodeService<=Proc{20674:system/1000} - Proc # 3: adj=vis /F trm= 0 21225:com.android.bluetooth/1002 (service) - com.android.bluetooth/.hfp.HeadsetService<=Proc{20674:system/1000} - Proc # 0: adj=vis /F trm= 0 20908:com.google.android.inputmethod.latin/u0a10035 (service) - com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME<=Proc{20674:system/1000} - Proc #34: adj=svc /B trm= 0 16765:com.google.android.apps.currents/u0a10012 (started-services) - Proc #14: adj=svc /B trm= 0 21148:com.google.android.gms/u0a10023 (started-services) - Proc #12: adj=home /B trm= 0 20989:com.android.launcher/u0a10036 (home) - Proc #37: adj=svcb /B trm= 0 15194:com.google.android.apps.googlevoice/u0a10089 (started-services) - Proc #17: adj=svcb /B trm= 0 24537:android.process.media/u0a10016 (started-services) - Proc #35: adj=bak /B trm= 0 16087:com.android.defcontainer/u0a10013 (service) - com.android.defcontainer/.DefaultContainerService<=Proc{16050:com.android.settings/1000} - Proc #16: adj=bak /B trm= 0 7334:com.google.android.gm/u0a10022 (bg-act) - Proc #15: adj=bak /B trm= 0 22499:com.google.android.googlequicksearchbox/u0a10060 (bg-act) - Proc # 9: adj=bak /B trm= 0 20856:com.google.android.gsf.login/u0a10023 (bg-empty) - Proc #26: adj=bak+1/B trm= 0 9923:com.android.mms/u0a10042 (bg-act) - Proc #23: adj=bak+1/B trm= 0 16721:com.android.chrome/u0a10010 (bg-act) - Proc #22: adj=bak+1/B trm= 0 17596:com.android.chrome:sandboxed_process0/u0a10010i33 (service) - com.android.chrome/org.chromium.content.app.SandboxedProcessService0<=Proc{16721:com.android.chrome/u0a10010} - Proc #19: adj=bak+1/B trm= 0 17442:com.google.android.youtube/u0a10067 (bg-services) - Proc #18: adj=bak+2/B trm= 0 16740:com.google.android.apps.plus/u0a10052 (bg-empty) - Proc #13: adj=bak+2/B trm= 0 7707:com.android.musicfx/u0a10044 (bg-empty) - Proc #36: adj=bak+3/B trm= 0 16050:com.android.settings/1000 (bg-act) - Proc #33: adj=bak+3/B trm= 0 16863:com.android.dialer/u0a10015 (bg-act) -</pre> - - -<p class="note"><strong>Note:</strong> The exact details of what is shown here will vary across -platform versions as process management policies are tweaked and improved.</p> - - -<p>Details on the highlighted sections are:</p> - -<ol> -<li>Foreground app: This is the current app running in the foreground -- it is in the "fore" memory -class because it is the top activity on the activity stack.</li> - -<li>Persistent processes: These are processes that are part of the core system that must always be -running.</li> - -<li>Dependent process: This shows how the Music app is using two processes. Its UI process has a -dependency on the "main" process (through a content provider). So while the UI process is in use, -the main process must also be kept around. This means the app's memory footprint is actually the -sum of both processes. You will have this kind of connection on a content provider any time you -have active calls into it or have unclosed cursors or file streams that came from it.</li> - -<li>Visible processes: These are processes that count in some way as "visible" to the user. This -generally means that it is either something the user can literally see (such as a process hosting a -paused but visible activity that is behind a non-full-screen dialog) or is something the user might -notice if the process disappeared (such as a foreground service playing music). You should be -certain that any process you have running at the "visible" level is indeed critical to the user, -because they are very expensive to the overall RAM load.</li> - -<li>Service processes: These are processes running long-term jobs in a service. This level of the -list is the start of less-critical processes, which the system has some freedom to kill if RAM is -needed elsewhere. These services are still quite expensive because they can be killed only -temporarily and the system tries to keep them running whenever possible.</li> - -<li>Home process: A special slot for the process that hosts the current Home activity, to try to -prevent it from being killed as much as possible. Killing this process is much more damaging to the -user experience than killing other cached processes, because so much user interaction goes through -home.</li> - -<li>Secondary service processes: These are services that have been running for a relatively long time -and so should be killed more aggressively when RAM is needed elsewhere.</li> - -<li>Cached processes: These are cached processes held in the LRU cache, which allow for fast app -switching and component launching. These processes are not required and the system will kill them -as needed to reclaim memory. You will often see a process hosting a running service here—this is -part of a platform policy of allowing very long-running services to drop down into the LRU list and -eventually be killed. If the service should continue running (as defined by the {@link -android.app.Service#onStartCommand onStartCommand()} return value, such as {@link -android.app.Service#START_STICKY}), the the system eventually restarts it. This avoids issues with -such services having memory leaks that over time reduce the number of regular cached processes that -can be kept.</li> - -</ol> - -<p>This numbered list of processes is essentially the LRU list of processes that the framework -provides to the kernel to help it determine which processes it should kill as it needs more RAM. -The kernel's out of memory killer will generally begin from the bottom of this list, killing the -last process and working its way up. It may not do it in exactly this order, as it can also take -into consideration other factors such as the relative RAM footprint of processes to some degree.</p> - -<p>There are many other options you can use with the activity command to analyze further details of -your app's state—use <code>adb shell dumpsys activity -h</code> for help on its use.</p> - ---> diff --git a/docs/html/training/articles/perf-tips.jd b/docs/html/training/articles/perf-tips.jd index 82de69a55249..30cab14d5da6 100644 --- a/docs/html/training/articles/perf-tips.jd +++ b/docs/html/training/articles/perf-tips.jd @@ -28,7 +28,8 @@ when combined, but it's unlikely that these changes will result in dramatic performance effects. Choosing the right algorithms and data structures should always be your priority, but is outside the scope of this document. You should use the tips in this document as general coding practices that you can incorporate into your habits for general code -efficiency.</p> +efficiency. +</p> <p>There are two basic rules for writing efficient code:</p> <ul> @@ -49,8 +50,7 @@ code for a device with a JIT is not always the best code for a device without.</p> <p>To ensure your app performs well across a wide variety of devices, ensure -your code is efficient at all levels and agressively optimize your performance.</p> - +your code is efficient at all levels and aggressively optimize your performance.</p> <h2 id="ObjectCreation">Avoid Creating Unnecessary Objects</h2> diff --git a/docs/html/training/auto/audio/index.jd b/docs/html/training/auto/audio/index.jd index 3a1b1e883494..65883671f956 100644 --- a/docs/html/training/auto/audio/index.jd +++ b/docs/html/training/auto/audio/index.jd @@ -596,7 +596,7 @@ href="https://www.youtube.com/watch?v=xc2HZSwPcwM"> </a> <h2 id="support_voice">Support Voice Actions</h2> -<p>To reduce driver distractions, you can add voice actions in your audio playback app. With voice +<p>To reduce driver distractions, you must add voice actions in your audio playback app. With voice action support, users can launch your app and play audio by providing voice input on Auto screens. If your audio playback app is already active and the user says <i>“Play a song”</i>, the system starts playing music without requiring the user to look at or touch diff --git a/docs/html/training/backup/autosyncapi.jd b/docs/html/training/backup/autosyncapi.jd deleted file mode 100644 index e0df7bb658ae..000000000000 --- a/docs/html/training/backup/autosyncapi.jd +++ /dev/null @@ -1,370 +0,0 @@ -page.title=Configuring Auto Backup for Apps -page.tags=backup, marshmallow, androidm -page.keywords=backup, autobackup -page.image=images/cards/card-auto-backup_2x.png - -@jd:body - -<div id="tb-wrapper"> -<div id="tb"> -<h2>This lesson teaches you to</h2> -<ol> - <li><a href="#configuring">Configure Data Backup</a></li> - <li><a href="#previous-androids">Support Lower Versions of Android</a></li> - <li><a href="#testing">Test Backup Configuration</a></li> - <li><a href="#issues">Handle Google Cloud Messaging</a></li> -</ol> - <h2>You should also read</h2> - <ul> - <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li> - <li><a href="{@docRoot}training/backup/backupapi.html">Using the Backup API</a> - </li> - </ul> - -</div> -</div> - -<p> - Users frequently invest time and effort to configure apps just the way they like them. Switching - to a new device can cancel out all that careful configuration. For apps whose <a href= - "{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">target SDK version</a> - is Android 6.0 (API level 23) and higher, devices running Android 6.0 and higher automatically - back up app data to the cloud. The system performs this automatic backup - for nearly all app data by default, and does so without your having to write any additional app - code. -</p> - -<p class="note"> -<strong>Note:</strong> To protect user privacy, the device user must have opted in to Google -services for Auto Backup to work. The Google services opt-in dialog appears when the user goes -through the Setup Wizard or configures the first Google account on the device. -</p> - -<p> - When a user installs your app on - a new device, or reinstalls your app on one (for example, after a factory reset), the system - automatically restores the app data from the cloud. This lesson provides information about how to - configure the Auto Backup for Apps feature, explaining its default behavior and how to - exclude data that you don't want the system to back up. -</p> - -<p> - The automatic backup feature preserves the data your app creates on a user device by uploading it - to the user’s Google Drive account and encrypting it. There is no charge to you or the user for - data storage, and the saved data does not count towards the user's personal Google Drive quota. - Each app can store up to 25MB. Once its backed-up data reaches 25MB, the app no longer sends - data to the cloud. If the system performs a data restore, it uses the last data snapshot that - the app had sent to the cloud. -</p> - -<p>Automatic backups occur when the following conditions are met:</p> - <ul> - <li>The device is idle.</li> - <li>The device is charging.</li> - <li>The device is connected to a Wi-Fi network.</li> - <li>At least 24 hours have elapsed since the last backup.</li> - </ul> -</p> - -<h2 id="configuring">Configure Data Backup</h2> - -<p> - On devices running Android 6.0 (API level 23) or higher, the default system behavior is to back up - almost all data that an app creates. The exception is <a href="#auto-exclude"> - automatically excluded data files</a>. This section explains how you can use settings in - your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> to further - limit and configure what data the system backs up. -</p> - -<h3 id="include-exclude">Including or excluding data</h3> - -<p> - Depending on what data your app needs and how you save it, you may need to set specific - rules for including or excluding certain files or directories. Auto Backup for Apps - lets you set these backup rules through the app manifest, in which you specify a backup scheme - configuration XML file. For example: -</p> - -<pre> -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="com.my.appexample"> - <uses-sdk android:minSdkVersion="23"/> - <uses-sdk android:targetSdkVersion="23"/> - <application ... -<strong> android:fullBackupContent="@xml/mybackupscheme"></strong> - </app> - ... -</manifest> -</pre> - -<p> - In this example, the <code>android:fullBackupContent</code> attribute specifies an XML file - called {@code mybackupscheme.xml}, which resides in the <code>res/xml/</code> directory of your - app development project. This configuration file contains rules controlling which files are backed - up. The following example code shows a configuration file that excludes a specific file, - {@code device_info.db}: -</p> - -<pre> -<?xml version="1.0" encoding="utf-8"?> -<full-backup-content> - <exclude domain="database" path="device_info.db"/> -</full-backup-content> -</pre> - -<h3 id="auto-exclude">Automatically excluded data files</h3> - -<p> - Most apps do not need to, and in fact should not, back up all data. For example, the system - should not back up temporary files and caches. For this reason, the automatic backup - service excludes certain data files by default: -</p> - -<ul> - <li>Files in the directories to which the - {@link android.content.Context#getCacheDir getCacheDir()} and - {@link android.content.Context#getCodeCacheDir getCodeCacheDir()} methods refer. - </li> - - <li>Files located on external storage, unless they reside in the directory to which the - {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method refers. - </li> - - <li>Files located in the directory to which the - {@link android.content.Context#getNoBackupFilesDir getNoBackupFilesDir()} method refers. - </li> -</ul> -<h3>Backup Configuration Syntax</h3> - -<p> - The backup service configuration allows you to specify what files to include or exclude from - backup. The syntax for the data backup configuration XML file is as follows: -</p> - -<pre> -<full-backup-content> - <include domain=["file" | "database" | "sharedpref" | "external" | "root"] - path="string" /> - <exclude domain=["file" | "database" | "sharedpref" | "external" | "root"] - path="string" /> -</full-backup-content> -</pre> - -<p> - The following elements and attributes allow you to specify the files to include in, and exclude - from, backup: -</p> - -<ul> - <li> - <code><include></code>: Specifies a set of resources to - back up, instead of having the system back up all data in your app by default. If you specify - an <code><include></code> element, the system backs up <em>only the resources specified</em> - with this element. You can specify multiple sets of resources to back up by using multiple - <code><include></code> elements - </li> - - <li> - <code><exclude></code>: Specifies any data you want the system to exclude - when it does a full backup. If you target the same set of resources with both the - <code><include></code> and <code><exclude></code> elements, - <code><exclude></code> takes precedence. - </li> - - <li> - <code>domain</code>: Specifies the type of resource you want to include in, - or exclude from, backup. Valid values for this attribute include: - - - - <ul> - <li> - <code>root</code>: Specifies that the resource is in the app’s root directory. - </li> - - <li> - <code>file</code>: Specifies a resource in the directory returned by the - {@link android.content.Context#getFilesDir getFilesDir()} method. - </li> - - <li> - <code>database</code>: Specifies a database that the - {@link android.content.Context#getDatabasePath getDatabasePath()} method returns, or that - the app interacts with via the {@link android.database.sqlite.SQLiteOpenHelper} class. - </li> - - <li> - <code>sharedpref</code>: Specifies a {@link android.content.SharedPreferences} object - that the {@link android.content.Context#getSharedPreferences getSharedPreferences()} - method returns. - </li> - - <li> - <code>external</code>: Specifies that the resource is in external storage, and corresponds - to a file in the directory that the - {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method returns. - </li> - </ul> - </li> - <li> - <code>path</code>: Specifies the file path to a resource that you want to include in, or - exclude from, backup. - </li> - - </li> -</ul> - - -<h3 id="disabling">Disabling data backups</h3> - -<p> - You can choose to prevent automatic backups of any of your app data by setting the - <code>android:allowBackup</code> attribute to <code>false</code> in the {@code app} element of - your manifest. This setting is illustrated in the following example: -</p> - -<pre> -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="com.my.appexample"> - <uses-sdk android:minSdkVersion="23"/> - <uses-sdk android:targetSdkVersion="23"/> - <application ... -<strong> android:allowBackup="false"></strong> - </application> - ... -</manifest> -</pre> - -<h2 id="previous-androids">Support Lower Versions of Android</h2> - -<p>There are two scenarios in which you may also need to support versions of Android lower -than 6.0 (API level 23): You may be updating your existing app to take advantage of the -new auto backup functionality in Android 6.0, while wanting -to continue supporting earlier versions of Android. Or you may be releasing a new app, but -want to make sure devices running on versions of Android predating 6.0 also have backup -functionality.</p> - -<h3 id="updating">Updating an existing app to support auto backup</h3> - -<p>Earlier versions of Android supported a key/value-pair-based backup mechanism, in which the app -defines a subclass of {@link android.app.backup.BackupAgent} and sets -<a href="{@docRoot}guide/topics/manifest/application-element.html#agent"> -{@code android:backupAgent}</a> in its -<a href="{@docRoot}guide/topics/manifest/application-element.html">app manifest</a>. If your app -used this legacy approach, you can transition to full-data backups by adding the -{@code android:fullBackupOnly="true"} attribute to the -<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application/>}</a> -element in the manifest. When running on a device with Android 5.1 -(API level 22) or lower, your app ignores this value in the manifest, and continues performing -backups in the previous manner.</p> - -<p>Even if you’re not using key/value backups, you can still use the approach described above to do -any custom processing in {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()} -or {@link android.app.backup.BackupAgent#onFullBackup onFullBackup()}. You can also use that -approach to receive a notification when a restore operation happens in -{@link android.app.backup.BackupAgent#onRestoreFinished onRestoreFinished()}. If you want to retain -the system's default implementation of -<a href="#include-exclude">XML include/exclude rules handling</a>, call -{@link android.app.backup.BackupAgent#onFullBackup super.onFullBackup()}.</p> - -<h3 id="lower-versions">Giving your new app support for lower versions of Android</h3> - -<p>If you are creating a new app that targets Android 6.0, but you also want to enable cloud backup -for devices running on Android 5.1 (API level 22) and lower, you must also -<a href="{@docRoot}training/backup/backupapi.html">implement the Backup API</a>.</p> - -<h2 id="testing">Test Backup Configuration</h2> - -<p> - Once you have created a backup configuration, you should test it to make sure your app saves data - and can restore it properly. -</p> - - -<h3>Enabling Backup Logging</h3> - -<p> - To help determine how the backup feature is parsing your XML file, enable logging before - performing a test backup: -</p> - -<pre class="no-pretty-print"> -$ adb shell setprop log.tag.BackupXmlParserLogging VERBOSE -</pre> - -<h3>Testing Backup</h3> - -<p>To manually run a backup, first initialize the Backup Manager by executing the following - command: -</p> - -<pre class="no-pretty-print"> -$ adb shell bmgr run -</pre> - -<p> - Next, manually back up your application using the following command. Use the - <code><PACKAGE></code> parameter to specify the package name for your app: -</p> - -<pre class="no-pretty-print"> -$ adb shell bmgr fullbackup <PACKAGE></pre> - - -<h3>Testing restore</h3> - -<p> - To manually initiate a restore after the system has backed up your app data, execute the following - command, using the <code><PACKAGE></code> parameter to specify the package name for your - app: -</p> - -<pre class="noprettyprint"> -$ adb shell bmgr restore <PACKAGE> -</pre> - -<p class="warning"> - <b>Warning:</b> This action stops your app and wipes its data before performing the restore - operation. -</p> - -<p> - You can test automatic restore for your app by uninstalling and reinstalling your app. The app - data is automatically restored from the cloud once the app installation is complete. -</p> - - -<h3>Troubleshooting backups</h3> - -<p> - If backup fails, you can clear the backup data and associated metadata either by turning backup - off and on in <strong>Settings > Backup</strong>, factory-resetting the device, or - executing this command: -</p> - -<pre>$ adb shell bmgr wipe <TRANSPORT> <PACKAGE></pre> - -<p> - You must prepend <code>com.google.android.gms</code> to the {@code <TRANSPORT>} value. - To get the list of <a href="{@docRoot}google/backup/index.html">transports</a>, execute the - following command: -</p> - -<pre>$ adb shell bmgr list transports</pre> - -<h2 id="gcm">Handle Google Cloud Messaging</h2> - - <p> - For apps that use <a href="https://developers.google.com/cloud-messaging/gcm">Google Cloud - Messaging</a> (GCM) for push notifications, backing up the registration - token that Google Cloud Messaging registration returned can cause unexpected behavior in - notifications for the restored app. This is because when a user installs your app on a new device, - the app must <a href="https://developers.google.com/cloud-messaging/android/client#sample-register"> - query the GCM API for a new registration token</a>. If the old registration is present, because the - system had backed it up and restored it, the app doesn't seek the new token. To prevent this issue - from arising, exclude the registration token from the set of backed-up files. - </p> diff --git a/docs/html/training/backup/backupapi.jd b/docs/html/training/backup/backupapi.jd deleted file mode 100644 index 2f3e93943f37..000000000000 --- a/docs/html/training/backup/backupapi.jd +++ /dev/null @@ -1,200 +0,0 @@ -page.title=Using the Backup API -parent.title=Backing up App Data to the Cloud -parent.link=index.html - -trainingnavtop=true - -next.title=Making the Most of Google Cloud Messaging -next.link=gcm.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="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li> - <li><a href="{@docRoot}training/backup/autosyncapi.html">Configuring Auto Backup for Apps</a> - (Android 6.0 (API level 23) and higher)</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. On versions of Android -prior to 6.0 (API level 23), app data is not restored by default, 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 class="note"> -<strong>Note:</strong> Devices running Android 6.0 and higher -<a href="{@docRoot}training/backup/autosyncapi.html">automatically back up</a> -nearly all data by default. -</p> - -<h2 id="register">Register for the Android Backup Service</h2> -<p>This lesson requires the use of the <a - href="{@docRoot}google/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> -<meta-data android:name="com.google.android.backup.api_key" -android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /> -</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> -<application android:label="MyApp" - android:backupAgent="TheBackupAgent"> - ... - <meta-data android:name="com.google.android.backup.api_key" - android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /> - ... -</application> -</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 - @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> -@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> diff --git a/docs/html/training/backup/index.jd b/docs/html/training/backup/index.jd deleted file mode 100644 index 4449fde1d5c3..000000000000 --- a/docs/html/training/backup/index.jd +++ /dev/null @@ -1,47 +0,0 @@ -page.title=Backing up App Data to the Cloud -page.tags=cloud,sync,backup - -trainingnavtop=true -startpage=true - -@jd:body - -<div id="tb-wrapper"> -<div id="tb"> - -<h2>Dependencies and prerequisites</h2> -<ul> - <li>Android 2.2 (API level 8) and higher</li> -</ul> -</div> -</div> - -<p>Users often invest significant time and effort creating data and setting -preferences within apps. Preserving that data for users if they replace a broken -device or upgrade to a new one is an important part of ensuring a great user -experience.</p> - -<p>This class covers techniques for backing up data to the cloud so that -users can restore their data when recovering from a data loss (such as a factory -reset) or installing your application on a new device.</p> - -<p>It is important to note that the API for cloud backup changed with the -release of Android 6.0 (API level 23). For your app to support backup both -on devices running Android 6.0, and those running Android 5.1 (API level -22) and lower, you must implement both techniques that this class explains.</p> - -<h2>Lessons</h2> - -<dl> - <dt><strong><a href="autosyncapi.html">Configuring Auto Backup for Apps</a></strong></dt> - <dd>This lesson applies to Android 6.0 (API level 23) and higher. Learn how to accomplish - seamless app data backup and restore with zero additional lines of application code.</dd> -</dl> - -<dl> - <dt><strong><a href="backupapi.html">Using the Backup API</a></strong></dt> - <dd>This lesson applies to Android 5.1 (API level 22) and lower. Learn how to integrate the Backup - API into your Android app, so all of that app's user data, such as preferences, notes, and high - scores, updates seamlessly across all devices linked to that Google account.</dd> -</dl> - diff --git a/docs/html/training/best-performance.jd b/docs/html/training/best-performance.jd index 8ea6fd5be4e5..bb88e990ce48 100644 --- a/docs/html/training/best-performance.jd +++ b/docs/html/training/best-performance.jd @@ -5,4 +5,9 @@ page.trainingcourse=true <p>These classes and articles help you build an app that's smooth, responsive, -and uses as little battery as possible.</p>
\ No newline at end of file +and uses as little battery as possible.</p> + +<p>Along with this section, you can find additional information about optimizing +your app in the <a href="/topic/performance/index.html">Performance and +Power</a> section.</p> + diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index d0dccba64d35..d2bf881859d5 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -649,25 +649,7 @@ </li> </ul> </li> - <li class="nav-section"> - <div class="nav-section-header"> - <a href="<?cs var:toroot ?>training/backup/index.html" - description= - "How to sync and back up app and user data to remote web services in the - cloud and how to restore the data back to multiple devices." - >Backing up App Data to the Cloud</a> - </div> - <ul> - <li><a href="<?cs var:toroot ?>training/backup/autosyncapi.html"> - Configuring Auto Backup - </a> - </li> - <li><a href="<?cs var:toroot ?>training/backup/backupapi.html"> - Using the Backup API - </a> - </li> - </ul> <li><a href="<?cs var:toroot ?>training/cloudsave/conflict-res.html" description= "How to design a robust conflict resolution strategy for apps that save data to the cloud." @@ -1888,6 +1870,12 @@ results." >Managing Your App's Memory</a> </li> <li> + <a href="<?cs var:toroot ?>training/articles/memory-overview.html" + description= + "How Android manages app process and memory allocation." + >Overview of Android Memory Management</a> + </li> + <li> <a href="<?cs var:toroot ?>training/articles/perf-tips.html" description= "How to optimize your app's performance in various ways to improve its diff --git a/docs/html/wear/preview/downloads.jd b/docs/html/wear/preview/downloads.jd index 08ed233afc8c..83a3f98452c8 100644 --- a/docs/html/wear/preview/downloads.jd +++ b/docs/html/wear/preview/downloads.jd @@ -626,7 +626,7 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement the accounts on the phone. </li> - <li>Choose a Google account to add and sync to your watch. + <li>Choose a Google Account to add and sync to your watch. </li> <li>Confirm the screen lock and enter the password to start the copying of @@ -647,8 +647,13 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement </h2> <p> - To test with the Android Emulator, create a virtual device in Android - Studio as follows: + To test with the Android Emulator, + confirm that you have the latest version of the <strong>Android SDK + Platform-tools</strong> from the <a href= + "{@docRoot}studio/intro/update.html#sdk-manager">SDK Manager</a>. + </p> + + <p>Create a new virtual device in Android Studio as follows: </p> <ol> @@ -659,8 +664,8 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement <li>Click <strong>Create Virtual Device</strong>. </li> - <li>In the <strong>Category</strong> pane, select Wear and - choose a hardware profile. + <li>In the <strong>Category</strong> pane, select <strong>Wear</strong> + and choose a hardware profile. The Android Wear 2.0 Developer Preview is only optimized for round devices currently, so we recommend not using the square or chin profiles for now. @@ -679,16 +684,66 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement <li>Verify the configuration of the Android Virtual Device (AVD) and click <strong>Finish</strong>. </li> + + <li>Start the emulator by selecting the new virtual device, clicking the + <strong>Play</strong> button, and waiting until + the emulator initializes and shows the Android Wear home screen. + </li> </ol> <p> - You can now test an application with a virtual preview device + Pair the phone with the emulator, and sync a Google Account, as follows: + </p> + + <ol> + <li>On the phone, install the Android Wear app from Google Play. + </li> + + <li>On the phone, enable Developer Options and USB Debugging. + </li> + + <li>Connect the phone to your computer through USB. + </li> + + <li>Forward the AVD's communication port to the connected handheld device + (each time the phone is connected):<br> + <code>adb -d forward tcp:5601 tcp:5601</code> + </li> + + <li>On the phone, in the Android Wear app, begin the standard pairing + process. For example, on the Welcome screen, tap the + <strong>Set It Up</strong> button. + Alternatively, if an existing watch already is paired, in the upper-left + drop-down, tap <strong>Add a New Watch</strong>. + </li> + + <li>On the phone, in the Android Wear app, tap the + Overflow button, and then tap + <strong>Pair with Emulator</strong>. + </li> + + <li>Tap the Settings icon. + </li> + + <li>Under Device Settings, tap <strong>Emulator</strong>. + </li> + + <li>Tap <strong>Accounts</strong> and select a Google Account, + and follow the steps in the wizard to + sync the account with the emulator. If necessary, type the screen-lock + device password, and Google Account password, to start the account sync. + </li> + </ol> + + <p> + You can now test an app with a virtual preview device in the <a href= "{@docRoot}tools/devices/emulator.html">Android Emulator</a>. For more information about using virtual devices, see <a href= - "{@docRoot}tools/devices/managing-avds.html">Managing AVDs with the AVD - Manager</a>. + "{@docRoot}tools/devices/managing-avds.html"> + Create and Manage Virtual Devices</a>. </p> + </div><!-- landing --> </div><!-- relative wrapper --> diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 7f3a4373639b..31019ce5e070 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -109,6 +109,9 @@ import java.util.Collection; * <li> <b>Nine Patch</b>: an extension to the PNG format allows it to * specify information about how to stretch it and place things inside of * it. + * <li><b>Vector</b>: a drawable defined in an XML file as a set of points, + * lines, and curves along with its associated color information. This type + * of drawable can be scaled without loss of display quality. * <li> <b>Shape</b>: contains simple drawing commands instead of a raw * bitmap, allowing it to resize better in some cases. * <li> <b>Layers</b>: a compound drawable, which draws multiple underlying |