BackupAgent compatible con versiones anteriores

Estoy buscando en el uso de la nueva API de copia de seguridad que están disponibles desde Android 2.2, pero es necesario mantener la compatibilidad hacia atrás (a 1,5 para ser exactos).

Los documentos indican:

El servicio de copia de seguridad y las API que debe utilizar están disponibles sólo en dispositivos que ejecutan API Level 8 (Android 2.2) o superior, por lo que también debe establecer el atributo android: minSdkVersion en "8". Sin embargo, si implementa compatibilidad retroactiva adecuada en su aplicación, puede admitir esta característica para dispositivos que ejecutan API de nivel 8 o superior, mientras siguen siendo compatibles con dispositivos antiguos.

De hecho, construir contra el nivel 8 targetSdkVersion con nivel 3 minSdkVersion y tratar de utilizar una clase de contenedor (con reflexión) para superar el problema de que la aplicación no se ejecutará si implementa una clase que extiende una clase inexistente.

Aquí está el problema: puesto que no hacemos llamadas reales a la clase de BackupHelper nosotros mismos, no podemos comprobar por adelantado si la clase realmente existe. (Como se explica en la documentación de Compatibilidad con versiones anteriores de Android con un método checkAvailable() .) La clase se instanciará y BackupAgent a un BackupAgent . Pero ya que utilizamos la reflexión, en realidad no sobrepasa BackupAgent y se produce una excepción en tiempo de ejecución cuando se solicita la copia de seguridad:

 java.lang.RuntimeException: Unable to create BackupAgent org.transdroid.service.BackupAgent: java.lang.ClassCastException: org.transdroid.service.BackupAgent 

Aquí está mi enfoque hacia un BackupAgent compatible con versiones anteriores: http://code.google.com/p/transdroid/source/browse/#svn/trunk/src/org/transdroid/service donde BackupAgent.java es el 'regular' BackupAgentHelper-extended class y BackupAgentHelperWrapper es la clase de contenedor basada en reflexión.

¿Alguien tiene éxito en la implementación de un BackupAgent con compatibilidad hacia atrás?

No veo por qué se topa con este problema.

Tengo el mismo problema: Quiero apoyar la copia de seguridad con una aplicación que admite también 1.5 (API 3).

No hay ningún problema en la creación de mi clase BackupAgentHelper , ya que esa clase nunca se llama desde mi propio código, sino desde el BackupManager es decir, el propio sistema. Por lo tanto no necesito envolverlo, y no veo porqué usted debe hacer eso:

  public class MyBackupAgentHelper extends BackupAgentHelper { @override onCreate() { \\do something usefull } 

Sin embargo, usted desea obtener una copia de seguridad en ejecución, para hacer que usted necesita para llamar a BackupManager.dataChanged() cada vez que sus datos cambian y desea informar al sistema de copia de seguridad (utilizando su BackupAgent o BackupAgentHelper ).

Es necesario que envuelva esa clase, ya que lo llama desde su código de aplicación.

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

A continuación, lo llama desde su código cuando cambia una preferencia o guarda algunos datos. Algún código de mi aplicación:

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

Así que, espero que esto funcione para usted!

(Si llama a la adb shell bmgr run cada vez que desee emular el sistema real iniciado backupprocess debería correctamente copia de seguridad y restaurar cuando vuelva a instalar la aplicación.)

Como alternativa, sólo puede utilizar la reflexión pura para hablar con el 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(); } } 

Apunte el android: backupAgent directamente en una clase v2.2; Nunca se cargará en una VM pre-v2.2, por lo que no habrá ningún problema de vinculación.

Debe establecer la versión minSDK a la siguiente:

 <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8"/> 

Y establecer el objetivo de compilación en sdk 8 (propiedades del proyecto en eclipse '.default.properties'):

 # Project target. target=android-8 

Ahora para llamar a nuevas cosas agregadas en SDK 8 tienes que usar la reflexión: http://developer.android.com/resources/articles/backward-compatibility.html

Me encontré con el mismo problema y aquí está lo que hice para resolverlo.

No extiende BackupAgent con el contenedor, lo amplía con la clase envuelta. Así que haces tu clase real de respaldo:

 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 } 

Bueno, y luego hacer un envoltorio como el desarrollador androide de compatibilidad con versiones anteriores dice que hacer. Tenga en cuenta que esta clase no extiende 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(); } 

}

Finalmente, en su manifiesto, declara el contenedor como su agente de copia de seguridad:

  <application android:label="@string/app_name" android:icon="@drawable/ic_launch_scale" android:backupAgent="WrapMyBackup" > 

Dado que el contenedor tiene los métodos adecuados definidos, no se producirá ningún problema cuando el gestor de copia de seguridad lo coloque en un BackupAgent. Dado que los niveles inferiores de API no tendrán un BackupManager, el código nunca se llamará, por lo que tampoco se ejecutará en ninguna excepción de ejecución.

Insted de simplemente llamar a BackupManager.dataChanged, compruebe si la clase existe primero.

  try { Class.forName("android.app.backup.BackupManager"); BackupManager.dataChanged(context.getPackageName()); } catch (ClassNotFoundException e) { } 

Qué tal si

  if (android.os.Build.VERSION.SDK_INT >= 8) { BackupManager bm = new BackupManager(this); bm.dataChanged(); } 
  • Interceptar llamadas de método
  • Android getOnTouchListener con la versión del API> = 15
  • Cargador de clases personalizado para android?
  • Clase personalizada que carga / reemplaza las clases nativas de Android
  • ¿Se puede usar la reflexión con métodos que pertenecen a un sdk mayor que el mínimo?
  • Invocación de un método privado (no publicado) en la API de Android
  • Obtener "java.lang.reflect.InvocationTargetException" al intentar registrar receptor de difusión de apk incrustado
  • Reflexión de Java para el método estático privado con parámetros
  • Protección contra la reflexión - android
  • Android Bluetooth no puede conectarse a dispositivos médicos con puerto fijo # - ¿utilizar reflexión de Java?
  • Cómo moverse repetición similar-variable en declaraciones if
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.