BackupAgent متوافق مع الوراء
-
28-09-2019 - |
سؤال
أنا أتطلع إلى استخدام واجهة برمجة تطبيقات النسخ الاحتياطي الجديد المتاح منذ Android 2.2 ، ولكن بحاجة إلى الحفاظ على التوافق للخلف (إلى 1.5 ليكون دقيقًا).
حالة المستندات:
تتوفر خدمة النسخ الاحتياطي وواجهة برمجة التطبيقات التي يجب استخدامها فقط على الأجهزة التي تعمل على تشغيل API من المستوى 8 (Android 2.2) أو أكبر ، لذلك يجب عليك أيضًا تعيين سمة Android: MinsDkversion إلى "8". ومع ذلك ، إذا قمت بتطبيق التوافق المتخلف بشكل صحيح في التطبيق الخاص بك ، فيمكنك دعم هذه الميزة للأجهزة التي تقوم بتشغيل API من المستوى 8 أو أكثر ، بينما تظل متوافقًا مع الأجهزة القديمة.
أنا بالفعل أبني ضد المستوى 8 targetSdkVersion
مع المستوى 3 minSdkVersion
وحاول استخدام فئة Wrapper (مع انعكاس) للتغلب على المشكلة التي لن يتم تشغيل التطبيق إذا قمت بتطبيق فئة تمتد فئة غير مرغوب فيها.
هذه هي المشكلة: نظرًا لأننا لا نقوم بإجراء مكالمات فعلية إلى BackupHelper
صفنا بأنفسنا ، لا يمكننا التحقق من المقدمة إذا كان الفصل موجودًا بالفعل. (كما هو موضح في وثائق التوافق مع الروبوت مع أ checkAvailable()
الطريقة) BackupAgent
. ولكن نظرًا لأننا نستخدم الانعكاس ، فإنه لا يتغلب في الواقع على Backupagent ويحدث استثناء في وقت التشغيل عند طلب النسخ الاحتياطي:
java.lang.RuntimeException: Unable to create BackupAgent org.transdroid.service.BackupAgent: java.lang.ClassCastException: org.transdroid.service.BackupAgent
هذا هو مقاربي في التوافق مع الوراء BackupAgent
: http://code.google.com/p/transdroid/source/browse/#svn/trunk/src/org/transdroid/service حيث backupagent.java هي فئة "العادية" التي تمتد BackupagentHelper و BackupagentHelperWrapper هي فئة التفاف القائمة على الانعكاس.
أي شخص ناجح في تنفيذ أ BackupAgent
مع توافق للخلف؟
المحلول
لا أرى لماذا واجهت هذه المشكلة.
لدي نفس المشكلة: أريد دعم النسخ الاحتياطي مع تطبيق يدعم أيضًا 1.5 (API 3).
لا توجد مشكلة في إنشاء بلدي BackupAgentHelper
الفصل ، لأن هذا الفصل لا يسمى أبدًا من الكود الخاص بي ، ولكن من BackupManager
أي النظام نفسه. لذلك لست بحاجة إلى لفه ، ولا أرى لماذا يجب أن تفعل ذلك:
public class MyBackupAgentHelper extends BackupAgentHelper {
@override onCreate()
{
\\do something usefull
}
ومع ذلك ، فأنت تريد الحصول على نسخة احتياطية ، للقيام بذلك تحتاج إلى الاتصال BackupManager.dataChanged()
كلما تغيرت بياناتك وتريد إبلاغ النظام بإجراء نسخ احتياطي (باستخدام الخاص بك BackupAgent
أو BackupAgentHelper
).
تحتاج إلى لف تلك الفئة ، لأنك تسميها من رمز التطبيق الخاص بك.
public class WrapBackupManager {
private BackupManager wrappedInstance;
static
{
try
{
Class.forName("android.app.backup.BackupManager");
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
public static void checkAvailable() {}
public void dataChanged()
{
wrappedInstance.dataChanged();
}
public WrapBackupManager(Context context)
{
wrappedInstance = new BackupManager(context);
}
}
ثم يمكنك الاتصال به من الكود الخاص بك عند تغيير التفضيل أو حفظ بعض البيانات. بعض التعليمات البرمجية من تطبيقي:
private static Boolean backupManagerAvailable = null;
private static void postCommitAction() {
if (backupManagerAvailable == null) {
try {
WrapBackupManager.checkAvailable();
backupManagerAvailable = true;
} catch (Throwable t) {
backupManagerAvailable = false;
}
}
if (backupManagerAvailable == true) {
Log.d("Fretter", "Backup Manager available, using it now.");
WrapBackupManager wrapBackupManager = new WrapBackupManager(
FretterApplication.getApplication());
wrapBackupManager.dataChanged();
} else {
Log.d("Fretter", "Backup Manager not available, not using it now.");
}
لذلك ، نأمل أن ينجح هذا من أجلك!
(إذا اتصلت adb shell bmgr run
في كل مرة تريد فيها محاكاة النظام الفعلي الذي بدأ المعالجة الخلفية ، يجب أن يقوم بنسخة احتياطية بشكل صحيح واستعادة عند إعادة تثبيت التطبيق.)
نصائح أخرى
كبديل ، يمكنك فقط استخدام انعكاس نقي للتحدث إلى Backupmanager:
public void scheduleBackup() {
Log.d(TAG, "Scheduling backup");
try {
Class managerClass = Class.forName("android.app.backup.BackupManager");
Constructor managerConstructor = managerClass.getConstructor(Context.class);
Object manager = managerConstructor.newInstance(context);
Method m = managerClass.getMethod("dataChanged");
m.invoke(manager);
Log.d(TAG, "Backup requested");
} catch(ClassNotFoundException e) {
Log.d(TAG, "No backup manager found");
} catch(Throwable t) {
Log.d(TAG, "Scheduling backup failed " + t);
t.printStackTrace();
}
}
أشر على Android: Backupagent مباشرة في فئة V2.2 ؛ لن يتم تحميله أبدًا على Pre-2.2 VM ، لذلك لن تكون هناك أي مشاكل في الارتباط.
تحتاج إلى تعيين إصدار minsdk على ما يلي:
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8"/>
وتعيين هدف البناء على SDK 8 (خصائص المشروع في Eclipse '.default.properties "):
# Project target.
target=android-8
الآن للاتصال بأشياء جديدة تمت إضافتها في SDK 8 ، عليك استخدام التأمل: http://developer.android.com/resources/articles/backward-compatibility.html
واجهت نفس المشكلة وهنا فعل ما فعلته للعمل.
أنت لا تمدد Backupagent مع Wrapper ، يمكنك تمديده مع الفصل الملف. لذلك أنت تصنع الخاص بك حقا فئة النسخ الاحتياطي:
public class MyBackup extends BackupAgent {
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
// TODO Auto-generated method stub
}
حسنًا ، ثم تقوم بعمل غلاف مثل مقالة التوافق المتخلف عن مطور Android. لاحظ أن هذه الفئة لا تمديد backupagent:
public class WrapMyBackup {
private MyBackup wb;
static {
try {
Class.forName("MyBackup");
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/** call this wrapped in a try/catch to see if we can instantiate **/
public static void checkAvailable() {}
public WrapMyBackup() {
wb = new MyBackup();
}
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
wb.onBackup(oldState, data, newState);
}
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
wb.onRestore(data, appVersionCode, newState);
}
public void onCreate() {
wb.onCreate();
}
public void onDestroy() {
wb.onDestroy();
}
}
أخيرًا ، في بيانك ، تعلن الغلاف كوكيل النسخ الاحتياطي الخاص بك:
<application
android:label="@string/app_name"
android:icon="@drawable/ic_launch_scale"
android:backupAgent="WrapMyBackup"
>
نظرًا لأن Wrapper الخاص بك لديه الطرق المناسبة المحددة ، فلن تواجه مشكلة عندما يقوم مدير النسخ الاحتياطي بإلقاءها على backupagent. نظرًا لأن مستويات API المنخفضة لن تحتوي على backupmanager ، فلن يتم استدعاء الكود أبدًا ، لذلك لن تواجه أي استثناءات وقت تشغيل هناك أيضًا.
insted من مجرد استدعاء backupmanager.datachanged ، تحقق مما إذا كان الفصل موجود أولاً.
try {
Class.forName("android.app.backup.BackupManager");
BackupManager.dataChanged(context.getPackageName());
} catch (ClassNotFoundException e) {
}
ماذا عن
if (android.os.Build.VERSION.SDK_INT >= 8)
{
BackupManager bm = new BackupManager(this);
bm.dataChanged();
}