重新安装后从SharedPreferences中检索值,并使用Android自动备份使用allowBackup = true进行检索

时间:2019-11-07 14:00:51

标签: android sharedpreferences

重新安装应用程序并具有allowBackup = true时,我无法从共享的“首选项”中检索值(在Android 9.0设备上)。

<manifest ... >
    ...
    <application android:allowBackup="true" ... >
        ...
    </application>
</manifest>

据此: https://developer.android.com/guide/topics/data/autobackup

应该恢复共享的首选项吗?

    SharedPreferences prefs = getSharedPreferences("TEST", MODE_PRIVATE);
    String name = prefs.getString("name", "No name defined");//"No name defined" is the default value.
    int idName = prefs.getInt("idName", 0); //0 is the default value.

    SharedPreferences.Editor editor = getSharedPreferences("TEST", MODE_PRIVATE).edit();
    editor.putString("name", "Elena");
    editor.putInt("idName", 12);
    editor.apply();
  • 我已经在(仿真器)电话(API 27)上登录了我的Gmail帐户, 驱动器应用程序,备份,应用程序数据,我看到18个应用程序,例如Youtube, Gmail等,还有我自己的应用。
  • 当我转到“设置>系统>备份”时,我看到相同的应用程序,也看到了自己的应用程序。我加载了应用程序,执行了sharedprefs代码。我关闭该应用程序并将其从内存中删除。然后按下“立即备份”按钮:

enter image description here

要验证,我可以在列表中看到我的应用,并且它在0分钟前得到了备份:

enter image description here

然后,我删除并重新安装该应用程序,并期望其中有2个值(Elena和12)。但是它们被删除了...

我也通过命令行尝试了同样的方法,但是也没有用: https://developer.android.com/guide/topics/data/testingbackup.html#Preparing

adb shell
dreamlte:/ $ bmgr enabled
Backup Manager currently enabled
dreamlte:/ $ bmgr list transports
    android/com.android.internal.backup.LocalTransport
    com.google.android.gms/.backup.migrate.service.D2dTransport
* com.google.android.gms/.backup.BackupTransportService
dreamlte:/ $ bmgr backupnow my.package.name
Running incremental backup for 1 requested packages.
Package @pm@ with result: Success
Package nl.dagelijkswoord.android with progress: 1536/309248
Package nl.dagelijkswoord.android with result: Success
Backup finished with result: Success

dreamlte:/ $ dumpsys backup
Backup Manager is enabled / provisioned / not pending init
Auto-restore is disabled
No backups running
Last backup pass started: 1573804513565 (now = 1573806675410)
  next scheduled: 1573819001046
...
1573806051616 : my.package.name

dreamlte:/ $ bmgr restore 1573806051616 my.package.name                                                                                                            
No matching restore set token.  Available sets:
  35e84268c94b7d9c : SM-G950F
  3a8e32898034f8af : SM-G950F
  3e2610c4ea45fb96 : Nexus 5X
done

dreamlte:/ $ bmgr restore 35e84268c94b7d9c my.package.name                                                                                                         
Scheduling restore: SM-G950F
restoreStarting: 1 packages
onUpdate: 0 = my.package.name 
restoreFinished: 0
done
  1. 删除应用
  2. 重新安装应用程序,并检查SharedPreferences值是否仍然存在。
  3. 值不见了...

在使用Samsung Cloud的Samsung设备上,此行为似乎也有所不同,但现在让我们集中关注股票Android。

更新:

由于我在build.gradle中降级了版本,因此它不再起作用:

build.gradle:
versionCode 70
versionName "1.6.1"

即使android:restoreAnyVersion="true"中有AndroidManifest,也只有在版本未降级时才有效。

6 个答案:

答案 0 :(得分:1)

默认情况下,如果设备已连接到Wi-Fi网络(如果设备用户尚未选择移动数据备份),则默认情况下android系统会备份所有默认数据,请尝试重新安装该应用程序并通常与WI-FI连接如果有任何更改,android系统每24小时同步一次数据。 您也可以尝试像这样指定自己的备份规则。

`<application 
 android:fullBackupContent="@xml/backup_rules">
</application>`

并创建一个xml文件,并将其放在 res / xml目录中。 在文件内部,使用和元素添加规则。以下示例备份了除device.xml之外的所有共享首选项。

`<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
</full-backup-content>`

我希望它能解决您的问题。

答案 1 :(得分:1)

根据数据备份文档,您需要创建SharedPreferencesBackupHelper并遵循这些steps来实现SharedPreferences备份,还需要register您案例的备份服务

答案 2 :(得分:1)

希望此过程对您有用。 尝试备份和还原用户的sharedPreferences。这样会将您的首选项备份到任何外部存储或设备。

用户卸载应用程序时,应将其备份。添加一些逻辑,如果外部存储或设备中存在文件,则将其还原。

使用以下代码备份您的偏好。

public static void backupUserPrefs(Context context) {
    final File prefsFile = new File(context.getFilesDir(), "../shared_prefs/" + context.getPackageName() + "_preferences.xml");
    final File backupFile = new File(context.getExternalFilesDir(null),
        "preferenceBackup.xml");
    String error = "";

    try {
        FileChannel src = new FileInputStream(prefsFile).getChannel();
        FileChannel dst = new FileOutputStream(backupFile).getChannel();

        dst.transferFrom(src, 0, src.size());

        src.close();
        dst.close();

        Toast toast = Toast.makeText(context, "Backed up user prefs to " + backupFile.getAbsolutePath(), Toast.LENGTH_SHORT);
        toast.show();
        return;
    } catch (FileNotFoundException e) {
        error = e.getMessage();
        e.printStackTrace();
    } catch (IOException e) {
        error = e.getMessage();
        e.printStackTrace();
    }

使用以下代码恢复首选项

public static boolean restoreUserPrefs(Context context) {
    final File backupFile = new File(context.getExternalFilesDir(null),
        "preferenceBackup.xml");
    String error = "";

    try {

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

        Editor editor = sharedPreferences.edit();

        InputStream inputStream = new FileInputStream(backupFile);

        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

        Document doc = docBuilder.parse(inputStream);
        Element root = doc.getDocumentElement();

        Node child = root.getFirstChild();
        while (child != null) {
            if (child.getNodeType() == Node.ELEMENT_NODE) {

                Element element = (Element) child;

                String type = element.getNodeName();
                String name = element.getAttribute("name");

                // In my app, all prefs seem to get serialized as either "string" or
                // "boolean" - this will need expanding if yours uses any other types!    
                if (type.equals("string")) {
                    String value = element.getTextContent();
                    editor.putString(name, value);
                } else if (type.equals("boolean")) {
                    String value = element.getAttribute("value");
                    editor.putBoolean(name, value.equals("true"));
                }
            }

            child = child.getNextSibling();

        }

        editor.commit();

        Toast toast = Toast.makeText(context, "Restored user prefs from " + backupFile.getAbsolutePath(), Toast.LENGTH_SHORT);
        toast.show();

        return true;

    } catch (FileNotFoundException e) {
        error = e.getMessage();
        e.printStackTrace();
    } catch (ParserConfigurationException e) {
        error = e.getMessage();
        e.printStackTrace();
    } catch (SAXException e) {
        error = e.getMessage();
        e.printStackTrace();
    } catch (IOException e) {
        error = e.getMessage();
        e.printStackTrace();
    }

    Toast toast = Toast.makeText(context, "Failed to restore user prefs from " + backupFile.getAbsolutePath() + " - " + error, Toast.LENGTH_SHORT);
    toast.show();

    return false;
}


    Toast toast = Toast.makeText(context, "Failed to Back up user prefs to " + backupFile.getAbsolutePath() + " - " + error, Toast.LENGTH_SHORT);
    toast.show();

}

然后重新启动您的应用,然后再使用这些功能

if (restoreUserPrefs(context)) {
    // Restart              
    AlarmManager alm = (AlarmManager) context.getSystemService(
    Context.ALARM_SERVICE);
    alm.set(AlarmManager.RTC,
    System.currentTimeMillis() + 1000, PendingIntent.getActivity(context, 0,
    new Intent(context, MainActivityName.class), 0));
    android.os.Process.sendSignal(android.os.Process.myPid(),
    android.os.Process.SIGNAL_KILL);
}

答案 3 :(得分:0)

您没有打开控制台消息中显示的自动恢复设置。您应该转到系统设置并将其打开。之后,恢复就可以了。

设置->备份->自动还原。

顺便说一句,您使用的令牌不正确。 1573806051616是时间戳而不是令牌。令牌应显示如下:

Ancestral packages: none
Ever backed up: XXXXXXXXXXXXXXXX

在这里,XXXXXXXXXXXXXXXX应该是令牌。

答案 4 :(得分:-1)

要测试还原,您需要运行以下命令而不删除您的应用程序。 restore命令将强制停止应用,擦除其数据并执行还原,从而模拟Android AutoBackup的功能:

bmgr restore <TOKEN> <PACKAGE>
运行备份命令时,从TOKEN命令中检索

logcat或从dumpsys backup命令中检索

dumpsys backup。您也可以检查$("<div/>", { width: "100px" }) 来验证备份是否已创建。

此处有更多信息:https://developer.android.com/guide/topics/data/testingbackup.html#TestingRestore

答案 5 :(得分:-1)

一种实现方法如下, (请注意,这可能不是最好的方法,但是可以!)

在卸载应用程序之前,请先备份它。添加一些逻辑,如果文件外部存储中存在,则将其还原。

  

存储在SharedPreferences类中的首选项保存到/data/data//shared_prefs/_preferences.xml中-备份很容易,您只需要将此文件的内容复制到外部存储中即可:

public static void backupUserPrefs(Context context) {
final File prefsFile = new File(context.getFilesDir(), "../shared_prefs/" + context.getPackageName() + "_preferences.xml");
final File backupFile = new File(context.getExternalFilesDir(null),
    "preferenceBackup.xml");
String error = "";

try {
    FileChannel src = new FileInputStream(prefsFile).getChannel();
    FileChannel dst = new FileOutputStream(backupFile).getChannel();

    dst.transferFrom(src, 0, src.size());

    src.close();
    dst.close();

    Toast toast = Toast.makeText(context, "Backed up user prefs to " + backupFile.getAbsolutePath(), Toast.LENGTH_SHORT);
    toast.show();
    return;
} catch (FileNotFoundException e) {
    error = e.getMessage();
    e.printStackTrace();
} catch (IOException e) {
    error = e.getMessage();
    e.printStackTrace();
}

使用以下代码恢复首选项

  

但是,还原操作带来了更大的挑战,因为shared_prefs文件不能由应用程序直接写入,并且SharedPrefs类不会直接公开其功能以从xml进行序列化。取而代之的是,您必须自己解析XML并将其推回。幸运的是,XML文件具有简单明了的结构,因此可以轻松地遍历元素并将其变回首选项。

if (restoreUserPrefs(context)) {
// Restart              
AlarmManager alm = (AlarmManager) context.getSystemService(
Context.ALARM_SERVICE);
alm.set(AlarmManager.RTC,
System.currentTimeMillis() + 1000, PendingIntent.getActivity(context, 0,
new Intent(context, MainActivityName.class), 0));
android.os.Process.sendSignal(android.os.Process.myPid(),
android.os.Process.SIGNAL_KILL);
}

注意:需要外部存储的读写权限。