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


9

重新安装应用程序并设置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代码。我关闭该应用程序并将其从内存中删除。然后按“立即备份”按钮:

在此处输入图片说明

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

在此处输入图片说明

然后,我删除并重新安装该应用程序,并期望其中有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. 重新安装App并检查SharedPreferences值是否仍然存在。
  3. 价值观消失了...

在具有Samsung Cloud的Samsung设备上,此行为似乎也有所不同,但现在让我们集中讨论常规的Android。

更新:

它不再工作了,因为我在build.gradle中降级了版本:

build.gradle:
versionCode 70
versionName "1.6.1"

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



您好@PraveenSP我想使用Android自动备份,而不是较旧的键/值存储版本。
吉姆·克莱蒙斯

Answers:


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>`

希望它能解决您的问题。


我只想保存sharedprefs,没有xml。
Jim Clermonts

上面的代码是android系统在用户驱动器上保存数据的规则,它不会保存为xml,Include&Exclude Tag通知系统哪些数据必须同步并保存,哪些数据必须在同步操作中排除。
Ashish srivastava

我了解但我认为这不必要吗?
吉姆·克莱蒙斯

1
我不认为这是不必要的原因,因为当android系统启动完成时,它会检查默认情况下配置在清单中的所有应用程序规则,当allowBackup为true时,它也会同步,但是当我们编写规则时,android系统会保留在本地规则中并将其与程序包名称相关联。
Ashish srivastava '19

我已经添加了上面的XML代码,但是没有任何区别。
Jim Clermonts


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

您好,问题是当build.gradle中的versionCode降级时,它不备份。这就是为什么它不起作用。仅存储一个简单的字符串就不需要这么多的代码。
吉姆·克莱蒙斯

为我工作...保存了我的一天...谢谢你
unownsp

0

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

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

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

Ancestral packages: none
Ever backed up: XXXXXXXXXXXXXXXX

在这里,XXXXXXXXXXXXXXXX应该是令牌。


-1

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

bmgr restore <TOKEN> <PACKAGE>

TOKENlogcat在运行备份命令或命令时从命令中检索dumpsys backup。您也可以检查dumpsys backup来验证是否已创建备份。

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


我尝试了此操作并编辑了答案,但是sharedpref值仍然不存在。
吉姆·克莱蒙斯

备份需要满足一些先决条件。请检查下面的链接:: blog.devknox.io/...
Susheel Tickoo

满足先决条件,并且不起作用。
吉姆·克莱蒙斯

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.