重新安装应用程序并具有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();
要验证,我可以在列表中看到我的应用,并且它在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
在使用Samsung Cloud的Samsung设备上,此行为似乎也有所不同,但现在让我们集中关注股票Android。
更新:
由于我在build.gradle中降级了版本,因此它不再起作用:
build.gradle:
versionCode 70
versionName "1.6.1"
即使android:restoreAnyVersion="true"
中有AndroidManifest
,也只有在版本未降级时才有效。
答案 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);
}
注意:需要外部存储的读写权限。