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