سؤال

أنا أتطلع إلى استخدام واجهة برمجة تطبيقات النسخ الاحتياطي الجديد المتاح منذ 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();
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top