Android 数据备份

Data Backup

Quickview

  • Back up the user's data to the cloud in case the user loses it
  • If the user upgrades to a new Android-powered device, your app can restore the user'sdata onto the new device
  • Easily back up SharedPreferences and private files with BackupAgentHelper
  • Requires API Level 8

In this document

  1. The Basics
  2. Declaring the Backup Agent in Your Manifest
  3. Registering for Android Backup Service
  4. Extending BackupAgent
    1. Required Methods
    2. Performing backup
    3. Performing restore
  5. Extending BackupAgentHelper
    1. Backing up SharedPreferences
    2. Backing up Private Files
  6. Checking the Restore Data Version
  7. Requesting Backup
  8. Requesting Restore
  9. Testing Your Backup Agent

Key classes

  1. BackupManager
  2. BackupAgent
  3. BackupAgentHelper

See also

  1. bmgr tool

Android's backup service allows you to copy your persistentapplication data to remote "cloud" storage, in order to provide a restore point for theapplication data and settings. If a user performs a factory reset or converts to a newAndroid-powered device, the system automatically restores your backup data when the applicationis re-installed. This way, your users don't need to reproduce their previous data orapplication settings. This process is completely transparent to the user and does not affect thefunctionality or user experience in your application.

During a backup operation (which your application can request), Android's Backup Manager (BackupManager) queries your application for backup data, then hands it toa backup transport, which then delivers the data to the cloud storage. During arestore operation, the Backup Manager retrieves the backup data from the backup transport andreturns it to your application so your application can restore the data to the device. It'spossible for your application to request a restore, but that shouldn't be necessary—Androidautomatically performs a restore operation when your application is installed and there existsbackup data associated with the user. The primary scenario in which backup data is restored is whena user resets their device or upgrades to a new device and their previously installedapplications are re-installed.

Note: The backup service is not designed forsynchronizing application data with other clients or saving data that you'd like to access duringthe normal application lifecycle. You cannot read or write backup data on demand and cannot accessit in any way other than through the APIs provided by the Backup Manager.

The backup transport is the client-side component of Android's backup framework, which iscustomizable bythe device manufacturer and service provider. The backup transport may differ from device to deviceand which backup transport is available on any given device is transparent to your application. TheBackup Manager APIs isolate your application from the actual backup transport available on a givendevice—your application communicates with the Backup Manager through a fixed set of APIs,regardless of the underlying transport.

Data backup is not guaranteed to be available on all Android-powereddevices. However, your application is not adversely affected in the eventthat a device does not provide a backup transport. If you believe that users will benefit from databackup in your application, then you can implement it as described in this document, test it, thenpublish your application without any concern about which devices actually perform backup. When yourapplication runs on a device that does not provide a backup transport, your application operatesnormally, but will not receive callbacks from the Backup Manager to backup data.

Although you cannot know what the current transport is, you are always assured that yourbackup data cannot be read by other applications on the device. Only the Backup Manager and backuptransport have access to the data you provide during a backup operation.

Caution: Because the cloud storage and transport service candiffer from device to device, Android makes no guarantees about the security of your data whileusing backup. You should always be cautious about using backup to store sensitive data, such asusernames and passwords.

The Basics

To backup your application data, you need to implement a backup agent. Your backupagent is called by the Backup Manager to provide the data you want to back up. It is also calledto restore your backup data when the application is re-installed. The Backup Manager handles allyour data transactions with the cloud storage (using the backup transport) and your backup agenthandles all your data transactions on the device.

To implement a backup agent, you must:

  1. Declare your backup agent in your manifest file with the android:backupAgent attribute.
  2. Register your application with a backup service. Google offers Android Backup Service as a backupservice for most Android-powered devices, which requires that you register your application inorder for it to work. Any other backup services available might also require you to registerin order to store your data on their servers.
  3. Define a backup agent by either:
    1. Extending BackupAgent

      The BackupAgent class provides the central interface withwhich your application communicates with the Backup Manager. If you extend this classdirectly, you must override onBackup() and onRestore() to handle the backup and restore operations for your data.

      Or

    2. Extending BackupAgentHelper

      The BackupAgentHelper class provides a convenientwrapper around the BackupAgent class, which minimizes the amount of codeyou need to write. In your BackupAgentHelper, you must use one or more"helper" objects, which automatically backup and restore certain types of data, so that you do notneed to implement onBackup() and onRestore().

      Android currently provides backup helpers that will backup and restore complete filesfrom SharedPreferences and internal storage.

Declaring the Backup Agent in Your Manifest

This is the easiest step, so once you've decided on the class name for your backup agent, declareit in your manifest with the android:backupAgent attribute in the <application> tag.

For example:

<manifest ... >
    ...
    <application android:label="MyApplication"
                 android:backupAgent="MyBackupAgent">
        <activity ... >
            ...
        </activity>
    </application>
</manifest>

Another attribute you might want to use is android:restoreAnyVersion. This attribute takes a boolean value to indicate whether youwant to restore the application data regardless of the current application version compared to theversion that produced the backup data. (The default value is "false".) See Checking the Restore Data Version for more information.

Note: The backup service and the APIs you must use areavailable only on devices running API Level 8 (Android 2.2) or greater, so you should alsoset your android:minSdkVersionattribute to "8". However, if you implement proper backward compatibility inyour application, you can support this feature for devices running API Level 8 or greater, whileremaining compatible with older devices.

Registering for Android Backup Service

Google provides a backup transport with Android Backup Service for mostAndroid-powered devices running Android 2.2 or greater.

In order for you application to perform backup using Android Backup Service, you mustregister your application with the service to receive a Backup Service Key, thendeclare the Backup Service Key in your Android manifest.

To get your Backup Service Key, register for Android Backup Service.When you register, you will be provided a Backup Service Key and the appropriate <meta-data> XML code for your Android manifest file, which you must include as a child of the<application> element. For example:

<application android:label="MyApplication"
             android:backupAgent="MyBackupAgent">
    ...
    <meta-data android:name="com.google.android.backup.api_key"
        android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" />
</application>

The android:name must be "com.google.android.backup.api_key" andthe android:value must be the Backup Service Key received from the Android BackupService registration.

If you have multiple applications, you must register each one, using the respective packagename.

Note: The backup transport provided by Android Backup Service isnot guaranteed to be availableon all Android-powered devices that support backup. Some devices might support backupusing a different transport, some devices might not support backup at all, and there is no way foryour application to know what transport is used on the device. However, if you implement backup foryour application, you should always include a Backup Service Key for Android Backup Service soyour application can perform backup when the device uses the Android Backup Service transport. Ifthe device does not use Android Backup Service, then the <meta-data> element with theBackup Service Key is ignored.

Extending BackupAgent

Most applications shouldn't need to extend the BackupAgent classdirectly, but should instead extend BackupAgentHelper to takeadvantage of the built-in helper classes that automatically backup and restore your files. However,you might want to extend BackupAgent directly if you need to:

  • Version your data format. For instance, if you anticipate the need to revise theformat in which you write your application data, you can build a backup agent to cross-check yourapplication version during a restore operation and perform any necessary compatibility work if theversion on the device is different than that of the backup data. For more information, see Checking the Restore Data Version.
  • Instead of backing up an entire file, you can specify the portions of data the should bebacked up and how each portion is then restored to the device. (This can also help you managedifferent versions, because you read and write your data as unique entities, rather thancomplete files.)
  • Back up data in a database. If you have an SQLite database that you want to restore whenthe user re-installs your application, you need to build a custom BackupAgent that reads the appropriate data during a backup operation, thencreate your table and insert the data during a restore operation.

If you don't need to perform any of the tasks above and want to back up complete files fromSharedPreferences or internal storage, youshould skip to Extending BackupAgentHelper.

Required Methods

When you create a backup agent by extending BackupAgent, youmust implement the following callback methods:

onBackup()
The Backup Manager calls this method after you request abackup. In this method, you read your application data from the device and pass the data youwant to back up to the Backup Manager, as described below in Performingbackup.
onRestore()
The Backup Manager calls this method during a restore operation (you can request a restore, but the system automatically performs restore whenthe user re-installs your application). When it calls this method, the Backup Manager delivers yourbackup data, which you then restore to the device, as described below in Performing restore.

Performing backup

When it's time to back up your application data, the Backup Manager calls your onBackup() method. This is where you must provide your application data to the Backup Manager soit can be saved to cloud storage.

Only the Backup Manager can call your backup agent's onBackup() method. Each time that your application data changes and you want to perform a backup,you must request a backup operation by calling dataChanged() (see RequestingBackup for more information). A backup request does not result in an immediate call to youronBackup() method. Instead, the Backup Manager waits for an appropriate time, then performsbackup for all applications that have requested a backup since the last backup was performed.

Tip: While developing your application, you can initiate animmediate backup operation from the Backup Manager with the bmgr tool.

When the Backup Manager calls your onBackup() method, it passes three parameters:

oldState
An open, read-only ParcelFileDescriptor pointing to the last backupstate provided by your application. This is not the backup data from cloud storage, but alocal representation of the data that was backed up the last time onBackup() was called (as defined by newState, below, or from onRestore()—more about this in the next section). Because onBackup() does not allow you to read existing backup data inthe cloud storage, you can use this local representation to determine whether your data has changedsince the last backup.
data
A BackupDataOutput object, which you use to deliver your backupdata to the Backup Manager.
newState
An open, read/write ParcelFileDescriptor pointing to a file in whichyou must write a representation of the data that you delivered to data (a representationcan be as simple as the last-modified timestamp for your file). This object isreturned as oldState the next time the Backup Manager calls your onBackup() method. If you do not write your backup data to newState, then oldStatewill point to an empty file next time Backup Manager calls onBackup().

Using these parameters, you should implement your onBackup() method to do the following:

  1. Check whether your data has changed since the last backup by comparing oldState toyour current data. How you read data in oldState depends on how you originally wrote it tonewState (see step 3). The easiest way to record the state of a file is with itslast-modified timestamp. For example, here's how you can read and compare a timestamp from oldState:
    // 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
    }

    If nothing has changed and you don't need to back up, skip to step 3.

  2. If your data has changed, compared to oldState, write the current data todata to back it up to the cloud storage.

    You must write each chunk of data as an "entity" in the BackupDataOutput. An entity is a flattened binary datarecord that is identified by a unique key string. Thus, the data set that you back up isconceptually a set of key-value pairs.

    To add an entity to your backup data set, you must:

    1. Call writeEntityHeader(), passing a unique string key for the data you're about to write and the datasize.
    2. Call writeEntityData(), passing a byte buffer that contains your data and the number of bytes to writefrom the buffer (which should match the size passed to writeEntityHeader()).

    For example, the following code flattens some data into a byte stream and writes it into asingle entity:

    // 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);

    Perform this for each piece of data that you want to back up. How you divide your data intoentities is up to you (and you might use just one entity).

  3. Whether or not you perform a backup (in step 2), write a representation of the current data tothe newState ParcelFileDescriptor. The Backup Manager retains this objectlocally as a representation of the data that is currently backed up. It passes this back to you asoldState the next time it calls onBackup() so you can determine whether another backup is necessary (as handled in step 1). If youdo not write the current data state to this file, thenoldState will be empty during the next callback.

    The following example saves a representation of the current data into newState usingthe file's last-modified timestamp:

    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    DataOutputStream out = new DataOutputStream(outstream);
    
    long modified = mDataFile.lastModified();
    out.writeLong(modified);

Caution: If your application data is saved to a file, make surethat you use synchronized statements while accessing the file so that your backup agent does notread the file while an Activity in your application is also writing the file.

Performing restore

When it's time to restore your application data, the Backup Manager calls your backupagent's onRestore() method. When it calls this method, the Backup Manager delivers your backup data soyou can restore it onto the device.

Only the Backup Manager can call onRestore(), which happens automatically when the system installs your application andfinds existing backup data. However, you can request a restore operation foryour application by calling requestRestore() (see Requesting restore for more information).

Note: While developing your application, you can also request arestore operation with the bmgrtool.

When the Backup Manager calls your onRestore() method, it passes three parameters:

data
A BackupDataInput, which allows you to read your backupdata.
appVersionCode
An integer representing the value of your application's android:versionCodemanifest attribute, as it was when this data was backed up. You can use this to cross-check thecurrent application version and determine if the data format is compatible. For moreinformation about using this to handle different versions of restore data, see the sectionbelow about Checking the Restore Data Version.
newState
An open, read/write ParcelFileDescriptor pointing to a file in whichyou must write the final backup state that was provided with data. This object isreturned as oldState the next time onBackup() is called. Recall that you must also write the same newState object in the onBackup() callback—also doing it here ensures that the oldState object given to onBackup() is valid even the first time onBackup() is called after the device is restored.

In your implementation of onRestore(), you should call readNextHeader() on thedata to iteratethrough all entities in the data set. For each entity found, do the following:

  1. Get the entity key with getKey().
  2. Compare the entity key to a list of known key values that you should have declared as staticfinal strings inside your BackupAgent class. When the key matches one ofyour known key strings, enter into a statement to extract the entity data and save it to the device:
    1. Get the entity data size with getDataSize() and create a byte array of that size.
    2. Call readEntityData() and pass it the byte array, which is where the data will go, and specify thestart offset and the size to read.
    3. Your byte array is now full and you can read the data and write it to the devicehowever you like.
  3. After you read and write your data back to the device, write the state of your data to thenewState parameter the same as you do during onBackup().

For example, here's how you can restore the data backed up by the example in the previoussection:

@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);
}

In this example, the appVersionCode parameter passed to onRestore() is not used. However, you might want to useit if you've chosen to perform backup when the user's version of the application has actually movedbackward (for example, the user went from version 1.5 of your app to 1.0). For more information, seethe section about Checking the Restore Data Version.

For an example implementation of BackupAgent, see the ExampleAgent class in the Backup and Restore sampleapplication.

Extending BackupAgentHelper

You should build your backup agent using BackupAgentHelper if you wantto back up complete files (from either SharedPreferences or internal storage).Building your backup agent with BackupAgentHelper requires far lesscode than extending BackupAgent, because you don't have to implementonBackup() and onRestore().

Your implementation of BackupAgentHelper mustuse one or more backup helpers. A backup helper is a specializedcomponent that BackupAgentHelper summons to perform backup andrestore operations for a particular type of data. The Android framework currently provides twodifferent helpers:

You can include multiple helpers in your BackupAgentHelper, but onlyone helper is needed for each data type. That is, if you have multiple SharedPreferences files, then you need only one SharedPreferencesBackupHelper.

For each helper you want to add to your BackupAgentHelper, you must dothe following during your onCreate() method:

  1. Instantiate in instance of the desired helper class. In the class constructor, you mustspecify the appropriate file(s) you want to backup.
  2. Call addHelper()to add the helper to your BackupAgentHelper.

The following sections describe how to create a backup agent using each of the availablehelpers.

Backing up SharedPreferences

When you instantiate a SharedPreferencesBackupHelper, you mustinclude the name of one or more SharedPreferences files.

For example, to back up a SharedPreferences file named"user_preferences", a complete backup agent using BackupAgentHelper lookslike this:

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);
    }
}

That's it! That's your entire backup agent. The SharedPreferencesBackupHelper includes all the codeneeded to backup and restore a SharedPreferences file.

When the Backup Manager calls onBackup() and onRestore(), BackupAgentHelper calls your backup helpers to performbackup and restore for your specified files.

Note: SharedPreferences are threadsafe, soyou can safely read and write the shared preferences file from your backup agent andother activities.

Backing up other files

When you instantiate a FileBackupHelper, you must include the name ofone or more files that are saved to your application's internal storage(as specified by getFilesDir(), which is the samelocation where openFileOutput() writesfiles).

For example, to backup two files named "scores" and "stats," a backup agent using BackupAgentHelper looks like this:

public class MyFileBackupAgent extends BackupAgentHelper {
    // The name of the SharedPreferences file
    static final String TOP_SCORES = "scores";
    static final String PLAYER_STATS = "stats";

    // A key to uniquely identify the set of backup data
    static final String FILES_BACKUP_KEY = "myfiles";

    // Allocate a helper and add it to the backup agent
    void onCreate() {
        FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS);
        addHelper(FILES_BACKUP_KEY, helper);
    }
}

The FileBackupHelper includes all the code necessary to backup andrestore files that are saved to your application's internal storage..

However, reading and writing to files on internal storage is not threadsafe. Toensure 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 intrinsiclock for the synchronized statements:

// Object for intrinsic lock
static final Object[] sDataLock = new Object[0];

Then create a synchronized statement with this lock each time you read or write the files. Forexample, here's a synchronized statement for writing the latest score in a game to a file:

try {
    synchronized (MyActivity.sDataLock) {
        File dataFile = new File(getFilesDir(), TOP_SCORES);
        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
        raFile.writeInt(score);
    }
} catch (IOException e) {
    Log.e(TAG, "Unable to write to file");
}

You should synchronize your read statements with the same lock.

Then, in your BackupAgentHelper, you must override onBackup() and onRestore() to synchronize the backup and restore operations with the sameintrinsic lock. For example, the MyFileBackupAgent example from above needs the followingmethods:

@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);
    }
}

That's it. All you need to do is add your FileBackupHelper in theonCreate() method and override onBackup() and onRestore() to synchronize read and write operations.

For an example implementation of BackupAgentHelper with FileBackupHelper, see theFileHelperExampleAgent class in the Backup and Restore sampleapplication.

Checking the Restore Data Version

When the Backup Manager saves your data to cloud storage, it automatically includes the versionof your application, as defined by your manifest file's android:versionCodeattribute. Before the Backup Manager calls your backup agent to restore your data, itlooks at the android:versionCode of the installed application and compares it to the valuerecorded in the restore data set. If the version recorded in the restore data set isnewer than the application version on the device, then the user has downgraded theirapplication. In this case, the Backup Manager will abort the restore operation for your applicationand not call your onRestore()method, because the restore set is considered meaningless to an older version.

You can override this behavior with the android:restoreAnyVersion attribute. This attribute is either "true" or "false" to indicate whether you want to restore the application regardless of the restore setversion. The default value is "false". If you define this to be "true" then theBackup Manager will ignore the android:versionCodeand call your onRestore()method in all cases. In doing so, you can manually check for the version difference in your onRestore()method and take any steps necessary to make the data compatible if the versions conflict.

To help you handle different versions during a restore operation, the onRestore()method passes you the version code included with the restore data set as the appVersionCodeparameter. You can then query the current application's version code with the PackageInfo.versionCode field. For example:

PackageInfo info;
try {
    String name = getPackageName();
    info = getPackageManager().getPackageInfo(name,0);
} catch (NameNotFoundException nnfe) {
    info = null;
}

int version;
if (info != null) {
    version = info.versionCode;
}

Then simply compare the version acquired from PackageInfoto the appVersionCode passed into onRestore().

Caution: Be certain you understand the consequences of settingandroid:restoreAnyVersion to "true" for your application. If each version of yourapplication that supports backup does not properly account for variations in your data format duringonRestore(),then the data on the device could be saved in a format incompatible with the version currentlyinstalled on the device.

Requesting Backup

You can request a backup operation at any time by calling dataChanged(). This method notifies the Backup Manager that you'dlike to backup your data using your backup agent. The Backup Manager then calls your backupagent's onBackup() method at an opportune time in the future. Typically, you shouldrequest a backup each time your data changes (such as when the user changes an applicationpreference that you'd like to back up). If you call dataChanged() several times consecutively, before the BackupManager requests a backup from your agent, your agent still receives just one call to onBackup().

Note: While developing your application, you can request abackup and initiate an immediate backup operation with the bmgrtool.

Requesting Restore

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 isinstalled. However, you can manually request a restore operation by calling requestRestore(), if necessary. Inwhich case, the Backup Manager calls your onRestore()implementation, passing the data from the current set of backup data.

Note: While developing your application, you can request arestore operation with the bmgrtool.

Testing Your Backup Agent

Once you've implemented your backup agent, you can test the backup and restore functionalitywith the following procedure, using bmgr.

  1. Install your application on a suitable Android system image
    • If using the emulator, create and use an AVD with Android 2.2 (API Level 8).
    • If using a device, the device must be running Android 2.2 or greater and have AndroidMarket built in.
  2. Ensure that backup is enabled
    • If using the emulator, you can enable backup with the following command from your SDKtools/ path:
      adb shell bmgr enable true
    • If using a device, open the system Settings, select Privacy, then enableBack up my data and Automatic restore.
  3. Open your application and initialize some data

    If you've properly implemented backup in your application, then it should request abackup each time the data changes. For example, each time the user changes some data, your appshould call dataChanged(), which adds a backup request tothe Backup Manager queue. For testing purposes, you can also make a request with the followingbmgr command:

    adb shell bmgr backup your.package.name
  4. Initiate a backup operation:
    adb shell bmgr run

    This forces the Backup Manager to perform all backup requests that are in itsqueue.

  5. Uninstall your application:
    adb uninstall your.package.name
  6. Re-install your application.

If your backup agent is successful, all the data you initialized in step 4 is restored.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值