1 page.title=Data Backup 2 @jd:body 3 4 5 <div id="qv-wrapper"> 6 <div id="qv"> 7 8 <h2>Quickview</h2> 9 <ul> 10 <li>Back up the user's data to the cloud in case the user loses it</li> 11 <li>If the user upgrades to a new Android-powered device, your app can restore the user's 12 data onto the new device</li> 13 <li>Easily back up SharedPreferences and private files with BackupAgentHelper</li> 14 <li>Requires API Level 8</li> 15 </ul> 16 17 <h2>In this document</h2> 18 <ol> 19 <li><a href="#Basics">The Basics</a></li> 20 <li><a href="#BackupManifest">Declaring the Backup Agent in Your Manifest</a></li> 21 <li><a href="#BackupKey">Registering for Android Backup Service</a></li> 22 <li><a href="#BackupAgent">Extending BackupAgent</a> 23 <ol> 24 <li><a href="#RequiredMethods">Required Methods</a></li> 25 <li><a href="#PerformingBackup">Performing backup</a></li> 26 <li><a href="#PerformingRestore">Performing restore</a></li> 27 </ol> 28 </li> 29 <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a> 30 <ol> 31 <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li> 32 <li><a href="#Files">Backing up Private Files</a></li> 33 </ol> 34 </li> 35 <li><a href="#RestoreVersion">Checking the Restore Data Version</a></li> 36 <li><a href="#RequestingBackup">Requesting Backup</a></li> 37 <li><a href="#RequestingRestore">Requesting Restore</a></li> 38 <li><a href="#Testing">Testing Your Backup Agent</a></li> 39 </ol> 40 41 <h2>Key classes</h2> 42 <ol> 43 <li>{@link android.app.backup.BackupManager}</li> 44 <li>{@link android.app.backup.BackupAgent}</li> 45 <li>{@link android.app.backup.BackupAgentHelper}</li> 46 </ol> 47 48 <h2>See also</h2> 49 <ol> 50 <li><a href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a></li> 51 </ol> 52 53 </div> 54 </div> 55 56 <p>Android's {@link android.app.backup backup} service allows you to copy your persistent 57 application data to remote "cloud" storage, in order to provide a restore point for the 58 application data and settings. If a user performs a factory reset or converts to a new 59 Android-powered device, the system automatically restores your backup data when the application 60 is re-installed. This way, your users don't need to reproduce their previous data or 61 application settings. This process is completely transparent to the user and does not affect the 62 functionality or user experience in your application.</p> 63 64 <p>During a backup operation (which your application can request), Android's Backup Manager ({@link 65 android.app.backup.BackupManager}) queries your application for backup data, then hands it to 66 a backup transport, which then delivers the data to the cloud storage. During a 67 restore operation, the Backup Manager retrieves the backup data from the backup transport and 68 returns it to your application so your application can restore the data to the device. It's 69 possible for your application to request a restore, but that shouldn't be necessary—Android 70 automatically performs a restore operation when your application is installed and there exists 71 backup data associated with the user. The primary scenario in which backup data is restored is when 72 a user resets their device or upgrades to a new device and their previously installed 73 applications are re-installed.</p> 74 75 <p class="note"><strong>Note:</strong> The backup service is <em>not</em> designed for 76 synchronizing application data with other clients or saving data that you'd like to access during 77 the normal application lifecycle. You cannot read or write backup data on demand and cannot access 78 it in any way other than through the APIs provided by the Backup Manager.</p> 79 80 <p>The backup transport is the client-side component of Android's backup framework, which is 81 customizable by 82 the device manufacturer and service provider. The backup transport may differ from device to device 83 and which backup transport is available on any given device is transparent to your application. The 84 Backup Manager APIs isolate your application from the actual backup transport available on a given 85 device—your application communicates with the Backup Manager through a fixed set of APIs, 86 regardless of the underlying transport.</p> 87 88 <p>Data backup is <em>not</em> guaranteed to be available on all Android-powered 89 devices. However, your application is not adversely affected in the event 90 that a device does not provide a backup transport. If you believe that users will benefit from data 91 backup in your application, then you can implement it as described in this document, test it, then 92 publish your application without any concern about which devices actually perform backup. When your 93 application runs on a device that does not provide a backup transport, your application operates 94 normally, but will not receive callbacks from the Backup Manager to backup data.</p> 95 96 <p>Although you cannot know what the current transport is, you are always assured that your 97 backup data cannot be read by other applications on the device. Only the Backup Manager and backup 98 transport have access to the data you provide during a backup operation.</p> 99 100 <p class="caution"><strong>Caution:</strong> Because the cloud storage and transport service can 101 differ from device to device, Android makes no guarantees about the security of your data while 102 using backup. You should always be cautious about using backup to store sensitive data, such as 103 usernames and passwords.</p> 104 105 106 <h2 id="Basics">The Basics</h2> 107 108 <p>To backup your application data, you need to implement a backup agent. Your backup 109 agent is called by the Backup Manager to provide the data you want to back up. It is also called 110 to restore your backup data when the application is re-installed. The Backup Manager handles all 111 your data transactions with the cloud storage (using the backup transport) and your backup agent 112 handles all your data transactions on the device.</p> 113 114 <p>To implement a backup agent, you must:</p> 115 116 <ol> 117 <li>Declare your backup agent in your manifest file with the <a 118 href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code 119 android:backupAgent}</a> attribute.</li> 120 <li>Register your application with a backup service. Google offers <a 121 href="http://code.google.com/android/backup/index.html">Android Backup Service</a> as a backup 122 service for most Android-powered devices, which requires that you register your application in 123 order for it to work. Any other backup services available might also require you to register 124 in order to store your data on their servers.</li> 125 <li>Define a backup agent by either:</p> 126 <ol type="a"> 127 <li><a href="#BackupAgent">Extending BackupAgent</a> 128 <p>The {@link android.app.backup.BackupAgent} class provides the central interface with 129 which your application communicates with the Backup Manager. If you extend this class 130 directly, you must override {@link 131 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 132 onBackup()} and {@link 133 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 134 onRestore()} to handle the backup and restore operations for your data.</p> 135 <p><em>Or</em></p> 136 <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a> 137 <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient 138 wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code 139 you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more 140 "helper" objects, which automatically backup and restore certain types of data, so that you do not 141 need to implement {@link 142 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 143 onBackup()} and {@link 144 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 145 onRestore()}.</p> 146 <p>Android currently provides backup helpers that will backup and restore complete files 147 from {@link android.content.SharedPreferences} and <a 148 href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p> 149 </li> 150 </ol> 151 </li> 152 </ol> 153 154 155 156 <h2 id="BackupManifest">Declaring the Backup Agent in Your Manifest</h2> 157 158 <p>This is the easiest step, so once you've decided on the class name for your backup agent, declare 159 it in your manifest with the <a 160 href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code 161 android:backupAgent}</a> attribute in the <a 162 href="{@docRoot}guide/topics/manifest/application-element.html">{@code 163 <application>}</a> tag.</p> 164 165 <p>For example:</p> 166 167 <pre> 168 <manifest ... > 169 ... 170 <application android:label="MyApplication" 171 <b>android:backupAgent="MyBackupAgent"</b>> 172 <activity ... > 173 ... 174 </activity> 175 </application> 176 </manifest> 177 </pre> 178 179 <p>Another attribute you might want to use is <a 180 href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code 181 android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you 182 want to restore the application data regardless of the current application version compared to the 183 version that produced the backup data. (The default value is "{@code false}".) See <a 184 href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p> 185 186 <p class="note"><strong>Note:</strong> The backup service and the APIs you must use are 187 available only on devices running API Level 8 (Android 2.2) or greater, so you should also 188 set your <a 189 href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a> 190 attribute to "8".</p> 191 192 193 194 195 <h2 id="BackupKey">Registering for Android Backup Service</h2> 196 197 <p>Google provides a backup transport with <a 198 href="http://code.google.com/android/backup/index.html">Android Backup Service</a> for most 199 Android-powered devices running Android 2.2 or greater.</p> 200 201 <p>In order for your application to perform backup using Android Backup Service, you must 202 register your application with the service to receive a Backup Service Key, then 203 declare the Backup Service Key in your Android manifest.</p> 204 205 <p>To get your Backup Service Key, <a 206 href="http://code.google.com/android/backup/signup.html">register for Android Backup Service</a>. 207 When you register, you will be provided a Backup Service Key and the appropriate {@code 208 <meta-data>} XML code for your Android manifest file, which you must include as a child of the 209 {@code <application>} element. For example:</p> 210 211 <pre> 212 <application android:label="MyApplication" 213 android:backupAgent="MyBackupAgent"> 214 ... 215 <meta-data android:name="com.google.android.backup.api_key" 216 android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" /> 217 </application> 218 </pre> 219 220 <p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and 221 the <code>android:value</code> must be the Backup Service Key received from the Android Backup 222 Service registration.</p> 223 224 <p>If you have multiple applications, you must register each one, using the respective package 225 name.</p> 226 227 <p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is 228 not guaranteed to be available 229 on all Android-powered devices that support backup. Some devices might support backup 230 using a different transport, some devices might not support backup at all, and there is no way for 231 your application to know what transport is used on the device. However, if you implement backup for 232 your application, you should always include a Backup Service Key for Android Backup Service so 233 your application can perform backup when the device uses the Android Backup Service transport. If 234 the device does not use Android Backup Service, then the {@code <meta-data>} element with the 235 Backup Service Key is ignored.</p> 236 237 238 239 240 <h2 id="BackupAgent">Extending BackupAgent</h2> 241 242 <p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class 243 directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take 244 advantage of the built-in helper classes that automatically backup and restore your files. However, 245 you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p> 246 <ul> 247 <li>Version your data format. For instance, if you anticipate the need to revise the 248 format in which you write your application data, you can build a backup agent to cross-check your 249 application version during a restore operation and perform any necessary compatibility work if the 250 version on the device is different than that of the backup data. For more information, see <a 251 href="#RestoreVersion">Checking the Restore Data Version</a>.</li> 252 <li>Instead of backing up an entire file, you can specify the portions of data the should be 253 backed up and how each portion is then restored to the device. (This can also help you manage 254 different versions, because you read and write your data as unique entities, rather than 255 complete files.)</li> 256 <li>Back up data in a database. If you have an SQLite database that you want to restore when 257 the user re-installs your application, you need to build a custom {@link 258 android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then 259 create your table and insert the data during a restore operation.</li> 260 </ul> 261 262 <p>If you don't need to perform any of the tasks above and want to back up complete files from 263 {@link android.content.SharedPreferences} or <a 264 href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you 265 should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p> 266 267 268 269 <h3 id="RequiredMethods">Required Methods</h3> 270 271 <p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you 272 must implement the following callback methods:</p> 273 274 <dl> 275 <dt>{@link 276 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 277 onBackup()}</dt> 278 <dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a 279 backup</a>. In this method, you read your application data from the device and pass the data you 280 want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing 281 backup</a>.</dd> 282 283 <dt>{@link 284 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 285 onRestore()}</dt> 286 <dd>The Backup Manager calls this method during a restore operation (you can <a 287 href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when 288 the user re-installs your application). When it calls this method, the Backup Manager delivers your 289 backup data, which you then restore to the device, as described below in <a 290 href="#PerformingRestore">Performing restore</a>.</dd> 291 </dl> 292 293 294 295 <h3 id="PerformingBackup">Performing backup</h3> 296 297 298 <p>When it's time to back up your application data, the Backup Manager calls your {@link 299 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 300 onBackup()} method. This is where you must provide your application data to the Backup Manager so 301 it can be saved to cloud storage.</p> 302 303 <p>Only the Backup Manager can call your backup agent's {@link 304 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 305 onBackup()} method. Each time that your application data changes and you want to perform a backup, 306 you must request a backup operation by calling {@link 307 android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting 308 Backup</a> for more information). A backup request does not result in an immediate call to your 309 {@link 310 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 311 onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs 312 backup for all applications that have requested a backup since the last backup was performed.</p> 313 314 <p class="note"><strong>Tip:</strong> While developing your application, you can initiate an 315 immediate backup operation from the Backup Manager with the <a 316 href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a>.</p> 317 318 <p>When the Backup Manager calls your {@link 319 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 320 onBackup()} method, it passes three parameters:</p> 321 322 <dl> 323 <dt>{@code oldState}</dt> 324 <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup 325 state provided by your application. This is not the backup data from cloud storage, but a 326 local representation of the data that was backed up the last time {@link 327 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 328 onBackup()} was called (as defined by {@code newState}, below, or from {@link 329 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 330 onRestore()}—more about this in the next section). Because {@link 331 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 332 onBackup()} does not allow you to read existing backup data in 333 the cloud storage, you can use this local representation to determine whether your data has changed 334 since the last backup.</dd> 335 <dt>{@code data}</dt> 336 <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup 337 data to the Backup Manager.</dd> 338 <dt>{@code newState}</dt> 339 <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which 340 you must write a representation of the data that you delivered to {@code data} (a representation 341 can be as simple as the last-modified timestamp for your file). This object is 342 returned as {@code oldState} the next time the Backup Manager calls your {@link 343 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 344 onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState} 345 will point to an empty file next time Backup Manager calls {@link 346 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 347 onBackup()}.</dd> 348 </dl> 349 350 <p>Using these parameters, you should implement your {@link 351 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 352 onBackup()} method to do the following:</p> 353 354 <ol> 355 <li>Check whether your data has changed since the last backup by comparing {@code oldState} to 356 your current data. How you read data in {@code oldState} depends on how you originally wrote it to 357 {@code newState} (see step 3). The easiest way to record the state of a file is with its 358 last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code 359 oldState}: 360 <pre> 361 // Get the oldState input stream 362 FileInputStream instream = new FileInputStream(oldState.getFileDescriptor()); 363 DataInputStream in = new DataInputStream(instream); 364 365 try { 366 // Get the last modified timestamp from the state file and data file 367 long stateModified = in.readLong(); 368 long fileModified = mDataFile.lastModified(); 369 370 if (stateModified != fileModified) { 371 // The file has been modified, so do a backup 372 // Or the time on the device changed, so be safe and do a backup 373 } else { 374 // Don't back up because the file hasn't changed 375 return; 376 } 377 } catch (IOException e) { 378 // Unable to read state file... be safe and do a backup 379 } 380 </pre> 381 <p>If nothing has changed and you don't need to back up, skip to step 3.</p> 382 </li> 383 <li>If your data has changed, compared to {@code oldState}, write the current data to 384 {@code data} to back it up to the cloud storage. 385 <p>You must write each chunk of data as an "entity" in the {@link 386 android.app.backup.BackupDataOutput}. An entity is a flattened binary data 387 record that is identified by a unique key string. Thus, the data set that you back up is 388 conceptually a set of key-value pairs.</p> 389 <p>To add an entity to your backup data set, you must:</p> 390 <ol> 391 <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int) 392 writeEntityHeader()}, passing a unique string key for the data you're about to write and the data 393 size.</li> 394 <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int) 395 writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write 396 from the buffer (which should match the size passed to {@link 397 android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li> 398 </ol> 399 <p>For example, the following code flattens some data into a byte stream and writes it into a 400 single entity:</p> 401 <pre> 402 // Create buffer stream and data output stream for our data 403 ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); 404 DataOutputStream outWriter = new DataOutputStream(bufStream); 405 // Write structured data 406 outWriter.writeUTF(mPlayerName); 407 outWriter.writeInt(mPlayerScore); 408 // Send the data to the Backup Manager via the BackupDataOutput 409 byte[] buffer = bufStream.toByteArray(); 410 int len = buffer.length; 411 data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len); 412 data.writeEntityData(buffer, len); 413 </pre> 414 <p>Perform this for each piece of data that you want to back up. How you divide your data into 415 entities is up to you (and you might use just one entity).</p> 416 </li> 417 <li>Whether or not you perform a backup (in step 2), write a representation of the current data to 418 the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object 419 locally as a representation of the data that is currently backed up. It passes this back to you as 420 {@code oldState} the next time it calls {@link 421 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 422 onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you 423 do not write the current data state to this file, then 424 {@code oldState} will be empty during the next callback. 425 <p>The following example saves a representation of the current data into {@code newState} using 426 the file's last-modified timestamp:</p> 427 <pre> 428 FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor()); 429 DataOutputStream out = new DataOutputStream(outstream); 430 431 long modified = mDataFile.lastModified(); 432 out.writeLong(modified); 433 </pre> 434 </li> 435 </ol> 436 437 <p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure 438 that you use synchronized statements while accessing the file so that your backup agent does not 439 read the file while an Activity in your application is also writing the file.</p> 440 441 442 443 444 <h3 id="PerformingRestore">Performing restore</h3> 445 446 <p>When it's time to restore your application data, the Backup Manager calls your backup 447 agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 448 onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so 449 you can restore it onto the device.</p> 450 451 <p>Only the Backup Manager can call {@link 452 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 453 onRestore()}, which happens automatically when the system installs your application and 454 finds existing backup data. However, you can request a restore operation for 455 your application by calling {@link 456 android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a 457 href="#RequestingRestore">Requesting restore</a> for more information).</p> 458 459 <p class="note"><strong>Note:</strong> While developing your application, you can also request a 460 restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr} 461 tool</a>.</p> 462 463 <p>When the Backup Manager calls your {@link 464 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 465 onRestore()} method, it passes three parameters:</p> 466 467 <dl> 468 <dt>{@code data}</dt> 469 <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup 470 data.</dd> 471 <dt>{@code appVersionCode}</dt> 472 <dd>An integer representing the value of your application's <a 473 href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a> 474 manifest attribute, as it was when this data was backed up. You can use this to cross-check the 475 current application version and determine if the data format is compatible. For more 476 information about using this to handle different versions of restore data, see the section 477 below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd> 478 <dt>{@code newState}</dt> 479 <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which 480 you must write the final backup state that was provided with {@code data}. This object is 481 returned as {@code oldState} the next time {@link 482 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 483 onBackup()} is called. Recall that you must also write the same {@code newState} object in the 484 {@link 485 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 486 onBackup()} callback—also doing it here ensures that the {@code oldState} object given to 487 {@link 488 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 489 onBackup()} is valid even the first time {@link 490 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 491 onBackup()} is called after the device is restored.</dd> 492 </dl> 493 494 <p>In your implementation of {@link 495 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 496 onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the 497 {@code data} to iterate 498 through all entities in the data set. For each entity found, do the following:</p> 499 500 <ol> 501 <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li> 502 <li>Compare the entity key to a list of known key values that you should have declared as static 503 final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of 504 your known key strings, enter into a statement to extract the entity data and save it to the device: 505 <ol> 506 <li>Get the entity data size with {@link 507 android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li> 508 <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int) 509 readEntityData()} and pass it the byte array, which is where the data will go, and specify the 510 start offset and the size to read.</li> 511 <li>Your byte array is now full and you can read the data and write it to the device 512 however you like.</li> 513 </ol> 514 </li> 515 <li>After you read and write your data back to the device, write the state of your data to the 516 {@code newState} parameter the same as you do during {@link 517 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 518 onBackup()}. 519 </ol> 520 521 <p>For example, here's how you can restore the data backed up by the example in the previous 522 section:</p> 523 524 <pre> 525 @Override 526 public void onRestore(BackupDataInput data, int appVersionCode, 527 ParcelFileDescriptor newState) throws IOException { 528 // There should be only one entity, but the safest 529 // way to consume it is using a while loop 530 while (data.readNextHeader()) { 531 String key = data.getKey(); 532 int dataSize = data.getDataSize(); 533 534 // If the key is ours (for saving top score). Note this key was used when 535 // we wrote the backup entity header 536 if (TOPSCORE_BACKUP_KEY.equals(key)) { 537 // Create an input stream for the BackupDataInput 538 byte[] dataBuf = new byte[dataSize]; 539 data.readEntityData(dataBuf, 0, dataSize); 540 ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf); 541 DataInputStream in = new DataInputStream(baStream); 542 543 // Read the player name and score from the backup data 544 mPlayerName = in.readUTF(); 545 mPlayerScore = in.readInt(); 546 547 // Record the score on the device (to a file or something) 548 recordScore(mPlayerName, mPlayerScore); 549 } else { 550 // We don't know this entity key. Skip it. (Shouldn't happen.) 551 data.skipEntityData(); 552 } 553 } 554 555 // Finally, write to the state blob (newState) that describes the restored data 556 FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor()); 557 DataOutputStream out = new DataOutputStream(outstream); 558 out.writeUTF(mPlayerName); 559 out.writeInt(mPlayerScore); 560 } 561 </pre> 562 563 <p>In this example, the {@code appVersionCode} parameter passed to {@link 564 android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use 565 it if you've chosen to perform backup when the user's version of the application has actually moved 566 backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see 567 the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p> 568 569 <div class="special"> 570 <p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a 571 href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code 572 ExampleAgent}</a> class in the <a 573 href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample 574 application.</p> 575 </div> 576 577 578 579 580 581 582 <h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2> 583 584 <p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want 585 to back up complete files (from either {@link android.content.SharedPreferences} or <a 586 href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>). 587 Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less 588 code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement 589 {@link 590 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 591 onBackup()} and {@link 592 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 593 onRestore()}.</p> 594 595 <p>Your implementation of {@link android.app.backup.BackupAgentHelper} must 596 use one or more backup helpers. A backup helper is a specialized 597 component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and 598 restore operations for a particular type of data. The Android framework currently provides two 599 different helpers:</p> 600 <ul> 601 <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link 602 android.content.SharedPreferences} files.</li> 603 <li>{@link android.app.backup.FileBackupHelper} to backup files from <a 604 href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li> 605 </ul> 606 607 <p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only 608 one helper is needed for each data type. That is, if you have multiple {@link 609 android.content.SharedPreferences} files, then you need only one {@link 610 android.app.backup.SharedPreferencesBackupHelper}.</p> 611 612 <p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do 613 the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p> 614 <ol> 615 <li>Instantiate in instance of the desired helper class. In the class constructor, you must 616 specify the appropriate file(s) you want to backup.</li> 617 <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()} 618 to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li> 619 </ol> 620 621 <p>The following sections describe how to create a backup agent using each of the available 622 helpers.</p> 623 624 625 626 <h3 id="SharedPreferences">Backing up SharedPreferences</h3> 627 628 <p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must 629 include the name of one or more {@link android.content.SharedPreferences} files.</p> 630 631 <p>For example, to back up a {@link android.content.SharedPreferences} file named 632 "user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks 633 like this:</p> 634 635 <pre> 636 public class MyPrefsBackupAgent extends BackupAgentHelper { 637 // The name of the SharedPreferences file 638 static final String PREFS = "user_preferences"; 639 640 // A key to uniquely identify the set of backup data 641 static final String PREFS_BACKUP_KEY = "prefs"; 642 643 // Allocate a helper and add it to the backup agent 644 @Override 645 public void onCreate() { 646 SharedPreferencesBackupHelper helper = 647 new SharedPreferencesBackupHelper(this, PREFS); 648 addHelper(PREFS_BACKUP_KEY, helper); 649 } 650 } 651 </pre> 652 653 <p>That's it! That's your entire backup agent. The {@link 654 android.app.backup.SharedPreferencesBackupHelper} includes all the code 655 needed to backup and restore a {@link android.content.SharedPreferences} file.</p> 656 657 <p>When the Backup Manager calls {@link 658 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 659 onBackup()} and {@link 660 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 661 onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform 662 backup and restore for your specified files.</p> 663 664 <p class="note"><strong>Note:</strong> {@link android.content.SharedPreferences} are threadsafe, so 665 you can safely read and write the shared preferences file from your backup agent and 666 other activities.</p> 667 668 669 670 <h3 id="Files">Backing up other files</h3> 671 672 <p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of 673 one or more files that are saved to your application's <a 674 href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a> 675 (as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same 676 location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes 677 files).</p> 678 679 <p>For example, to backup two files named "scores" and "stats," a backup agent using {@link 680 android.app.backup.BackupAgentHelper} looks like this:</p> 681 682 <pre> 683 public class MyFileBackupAgent extends BackupAgentHelper { 684 // The name of the file 685 static final String TOP_SCORES = "scores"; 686 static final String PLAYER_STATS = "stats"; 687 688 // A key to uniquely identify the set of backup data 689 static final String FILES_BACKUP_KEY = "myfiles"; 690 691 // Allocate a helper and add it to the backup agent 692 @Override 693 public void onCreate() { 694 FileBackupHelper helper = new FileBackupHelper(this, 695 TOP_SCORES, PLAYER_STATS); 696 addHelper(FILES_BACKUP_KEY, helper); 697 } 698 } 699 </pre> 700 701 <p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and 702 restore files that are saved to your application's <a 703 href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p> 704 705 <p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To 706 ensure that your backup agent does not read or write your files at the same time as your activities, 707 you must use synchronized statements each time you perform a read or write. For example, 708 in any Activity where you read and write the file, you need an object to use as the intrinsic 709 lock for the synchronized statements:</p> 710 711 <pre> 712 // Object for intrinsic lock 713 static final Object sDataLock = new Object(); 714 </pre> 715 716 <p>Then create a synchronized statement with this lock each time you read or write the files. For 717 example, here's a synchronized statement for writing the latest score in a game to a file:</p> 718 719 <pre> 720 try { 721 synchronized (MyActivity.sDataLock) { 722 File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES); 723 RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw"); 724 raFile.writeInt(score); 725 } 726 } catch (IOException e) { 727 Log.e(TAG, "Unable to write to file"); 728 } 729 </pre> 730 731 <p>You should synchronize your read statements with the same lock.</p> 732 733 <p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link 734 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 735 onBackup()} and {@link 736 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 737 onRestore()} to synchronize the backup and restore operations with the same 738 intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following 739 methods:</p> 740 741 <pre> 742 @Override 743 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 744 ParcelFileDescriptor newState) throws IOException { 745 // Hold the lock while the FileBackupHelper performs backup 746 synchronized (MyActivity.sDataLock) { 747 super.onBackup(oldState, data, newState); 748 } 749 } 750 751 @Override 752 public void onRestore(BackupDataInput data, int appVersionCode, 753 ParcelFileDescriptor newState) throws IOException { 754 // Hold the lock while the FileBackupHelper restores the file 755 synchronized (MyActivity.sDataLock) { 756 super.onRestore(data, appVersionCode, newState); 757 } 758 } 759 </pre> 760 761 <p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the 762 {@link android.app.backup.BackupAgent#onCreate()} method and override {@link 763 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 764 onBackup()} and {@link 765 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) 766 onRestore()} to synchronize read and write operations.</p> 767 768 <div class="special"> 769 <p>For an example implementation of {@link 770 android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the 771 {@code FileHelperExampleAgent} class in the <a 772 href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample 773 application.</p> 774 </div> 775 776 777 778 779 780 781 <h2 id="RestoreVersion">Checking the Restore Data Version</h2> 782 783 <p>When the Backup Manager saves your data to cloud storage, it automatically includes the version 784 of your application, as defined by your manifest file's <a 785 href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a> 786 attribute. Before the Backup Manager calls your backup agent to restore your data, it 787 looks at the <a 788 href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code 789 android:versionCode}</a> of the installed application and compares it to the value 790 recorded in the restore data set. If the version recorded in the restore data set is 791 <em>newer</em> than the application version on the device, then the user has downgraded their 792 application. In this case, the Backup Manager will abort the restore operation for your application 793 and not call your {@link 794 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} 795 method, because the restore set is considered meaningless to an older version.</p> 796 797 <p>You can override this behavior with the <a 798 href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code 799 android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code 800 false}" to indicate whether you want to restore the application regardless of the restore set 801 version. The default value is "{@code false}". If you define this to be "{@code true}" then the 802 Backup Manager will ignore the <a 803 href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a> 804 and call your {@link 805 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} 806 method in all cases. In doing so, you can manually check for the version difference in your {@link 807 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} 808 method and take any steps necessary to make the data compatible if the versions conflict.</p> 809 810 <p>To help you handle different versions during a restore operation, the {@link 811 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} 812 method passes you the version code included with the restore data set as the {@code appVersionCode} 813 parameter. You can then query the current application's version code with the {@link 814 android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p> 815 816 <pre> 817 PackageInfo info; 818 try { 819 String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}(); 820 info = {@link android.content.ContextWrapper#getPackageManager 821 getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int) 822 getPackageInfo}(name,0); 823 } catch (NameNotFoundException nnfe) { 824 info = null; 825 } 826 827 int version; 828 if (info != null) { 829 version = info.versionCode; 830 } 831 </pre> 832 833 <p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo} 834 to the {@code appVersionCode} passed into {@link 835 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}. 836 </p> 837 838 <p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting 839 <a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code 840 android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your 841 application that supports backup does not properly account for variations in your data format during 842 {@link 843 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}, 844 then the data on the device could be saved in a format incompatible with the version currently 845 installed on the device.</p> 846 847 848 849 <h2 id="RequestingBackup">Requesting Backup</h2> 850 851 <p>You can request a backup operation at any time by calling {@link 852 android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd 853 like to backup your data using your backup agent. The Backup Manager then calls your backup 854 agent's {@link 855 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 856 onBackup()} method at an opportune time in the future. Typically, you should 857 request a backup each time your data changes (such as when the user changes an application 858 preference that you'd like to back up). If you call {@link 859 android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup 860 Manager requests a backup from your agent, your agent still receives just one call to {@link 861 android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) 862 onBackup()}.</p> 863 864 <p class="note"><strong>Note:</strong> While developing your application, you can request a 865 backup and initiate an immediate backup operation with the <a 866 href="{@docRoot}tools/help/bmgr.html">{@code bmgr} 867 tool</a>.</p> 868 869 870 <h2 id="RequestingRestore">Requesting Restore</h2> 871 872 <p>During the normal life of your application, you shouldn't need to request a restore operation. 873 They system automatically checks for backup data and performs a restore when your application is 874 installed. However, you can manually request a restore operation by calling {@link 875 android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In 876 which case, the Backup Manager calls your {@link 877 android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} 878 implementation, passing the data from the current set of backup data.</p> 879 880 <p class="note"><strong>Note:</strong> While developing your application, you can request a 881 restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr} 882 tool</a>.</p> 883 884 885 <h2 id="Testing">Testing Your Backup Agent</h2> 886 887 <p>Once you've implemented your backup agent, you can test the backup and restore functionality 888 with the following procedure, using <a 889 href="{@docRoot}tools/help/bmgr.html">{@code bmgr}</a>.</p> 890 891 <ol> 892 <li>Install your application on a suitable Android system image 893 <ul> 894 <li>If using the emulator, create and use an AVD with Android 2.2 (API Level 8).</li> 895 <li>If using a device, the device must be running Android 2.2 or greater and have Google 896 Play built in.</li> 897 </ul> 898 </li> 899 <li>Ensure that backup is enabled 900 <ul> 901 <li>If using the emulator, you can enable backup with the following command from your SDK 902 {@code tools/} path: 903 <pre class="no-pretty-print">adb shell bmgr enable true</pre> 904 </li> 905 <li>If using a device, open the system <b>Settings</b>, select 906 <b>Backup & reset</b>, then enable 907 <b>Back up my data</b> and <b>Automatic restore</b>.</li> 908 </ul> 909 </li> 910 <li>Open your application and initialize some data 911 <p>If you've properly implemented backup in your application, then it should request a 912 backup each time the data changes. For example, each time the user changes some data, your app 913 should call {@link android.app.backup.BackupManager#dataChanged()}, which adds a backup request to 914 the Backup Manager queue. For testing purposes, you can also make a request with the following 915 {@code bmgr} command:</p> 916 <pre class="no-pretty-print">adb shell bmgr backup <em>your.package.name</em></pre> 917 </li> 918 <li>Initiate a backup operation: 919 <pre class="no-pretty-print">adb shell bmgr run</pre> 920 <p>This forces the Backup Manager to perform all backup requests that are in its 921 queue.</p> 922 <li>Uninstall your application: 923 <pre class="no-pretty-print">adb uninstall <em>your.package.name</em></pre> 924 </li> 925 <li>Re-install your application.</li> 926 </ol> 927 928 <p>If your backup agent is successful, all the data you initialized in step 4 is restored.</p> 929 930 931