Обратная совместимость BackupAgent

Я изучаю использование нового API резервного копирования, доступного с Android 2.2, но ему необходимо поддерживать обратную совместимость (точнее, до 1,5).

В документах указано:

Служба резервного копирования и API, которые вы должны использовать, доступны только на устройствах с уровнем API 8 (Android 2.2) или выше, поэтому вы также должны установить свой атрибут android: minSdkVersion на «8». Однако, если вы реализуете надлежащую обратную совместимость в своем приложении, вы можете поддерживать эту функцию для устройств с уровнем API 8 или выше, оставаясь совместимым со старыми устройствами.

Я действительно targetSdkVersion против 8-го уровня targetSdkVersion с уровнем 3 minSdkVersion и пытаюсь использовать класс-оболочку (с отражением) для преодоления проблемы, которую приложение не будет выполнять, если вы реализуете класс, который расширяет несуществующий класс.

Вот в чем проблема: поскольку мы сами не делаем настоящих вызовов класса BackupHelper , мы не можем проверить, действительно ли класс действительно существует. (Как поясняется в документации Android Backward Compatibility с помощью checkAvailable() .) Таким образом, класс будет создан и BackupAgent в 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 с обратной совместимостью?

Solutions Collecting From Web of "Обратная совместимость 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 каждый раз, когда хотите эмулировать фактический инициированный системой backupprocess, он должен правильно выполнять резервное копирование и восстановление при повторной установке приложения.)

В качестве альтернативы вы можете просто использовать чистое отражение, чтобы поговорить с 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(); } } 

Укажите андроид: backupAgent прямо в классе v2.2; Он никогда не будет загружен на pre-v2.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 на оболочку, вы расширяете ее с помощью завернутого класса. Таким образом, вы создаете свой настоящий класс резервного копирования:

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

Поскольку ваша оболочка имеет определенные методы, вы не столкнетесь с проблемой, когда менеджер резервного копирования передает ее в BackupAgent. Поскольку более низкие уровни API не будут иметь BackupManager, код никогда не будет вызван, поэтому вы не столкнетесь с каким-либо исключением.

Если вы только что вызвали 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(); }