Question

Je cherche en utilisant la nouvelle API de sauvegarde qui est disponible depuis Android 2.2, mais nécessité de maintenir une compatibilité ascendante (à 1,5 pour être exact).

L'état docs:

  

Le service de sauvegarde et les API, vous devez utiliser ne sont disponibles que sur les appareils fonctionnant API Niveau 8 (Android 2.2) ou plus, vous devez également définir votre attribut android: minSdkVersion à « 8 ». Toutefois, si vous implémentez rétrocompatibilité approprié dans votre application, vous pouvez prendre en charge cette fonctionnalité pour les périphériques API en cours d'exécution de niveau 8 ou plus, tout en restant compatible avec les appareils plus anciens.

Je fait construire par rapport au niveau 8 targetSdkVersion avec le niveau 3 minSdkVersion et essayez d'utiliser une classe wrapper (avec réflexion) pour résoudre le problème que l'application ne fonctionnera pas si vous implémentez une classe qui étend une classe non existant.

Voici le problème: puisque nous ne faisons pas les appels réels à la classe BackupHelper nous-mêmes, nous ne pouvons pas vérifier dès le départ si la classe existe bel et bien. (Comme il est expliqué dans la documentation rétrocompatibilité Android avec une méthode checkAvailable().) La classe sera donc instancié et jeté à un BackupAgent. Mais puisque nous utilisons la réflexion, il ne remplace pas réellement BackupAgent et une exception se produit lors de l'exécution lorsque la sauvegarde est demandée:

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

Voici mon approche à un BackupAgent rétrocompatible: http://code.google.com/p/transdroid/source/browse/#svn/trunk/src/org/transdroid/service où le BackupAgent.java est le 'régulier' BackupAgentHelper d'allongement de classe et BackupAgentHelperWrapper est la classe enveloppe par réflexion.

Toute personne mise en œuvre d'un Successfull BackupAgent avec compatibilité ascendante?

Était-ce utile?

La solution

Je ne vois pas pourquoi vous rencontrez ce problème.

J'ai le même problème. Je veux sauvegarde de support avec une application qui prend également en charge 1,5 (API 3)

Il n'y a pas de problème dans la création de ma classe BackupAgentHelper, puisque cette classe est jamais appelé de mon propre code, mais à partir du BackupManager dire que le système lui-même. Par conséquent, je ne ai pas besoin de l'envelopper, et je ne vois pas pourquoi vous devriez faire que:

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

Cependant, vous ne voulez obtenir un fonctionnement de secours, de faire que vous avez besoin de faire appel à BackupManager.dataChanged() chaque fois que vos modifications de données et que vous souhaitez informer le système de sauvegarde (à l'aide de votre BackupAgent ou BackupAgentHelper).

Vous avez besoin d'envelopper cette classe, puisque vous l'appelez de votre code d'application.


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

}

Vous appelez ensuite de votre code lorsque vous modifiez une préférence ou de sauvegarde des données. Une partie du code de mon application:


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

Alors, espérons que cela fonctionne pour vous!

(Si vous appelez adb shell bmgr run chaque fois que vous voulez imiter le système réel initié backupprocess il se doit correctement sauvegarde et de restauration lorsque vous réinstallez l'application.)

Autres conseils

Comme alternative, vous pouvez simplement utiliser la réflexion pure pour parler à la 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();
    }
}

point l'androïde: BackupAgent droit à une classe v2.2; il ne sera jamais chargé sur un pré-VM V2.2, donc il n'y aura pas de problème de liaison.

Vous devez définir la version minSDK à ce qui suit:

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

et le réglage de la cible de construction à 8 (SDK propriétés du projet dans Eclipse » .default.properties'):

# Project target.
target=android-8

Maintenant, pour appeler de nouvelles choses ajouté dans SDK 8 que vous avez à la réflexion utilisation: http://developer.android.com/resources/articles/backward-compatibility.html

Je couru dans le même problème et voici ce que je l'ai fait travailler dehors.

Vous ne couvre pas BackupAgent avec l'emballage, vous étendez avec la classe enveloppé. Alors vous faites votre réel classe de sauvegarde:

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

}

D'accord, et vous faire une enveloppe comme article de compatibilité du développeur Android a dit de faire. Notez que cette classe ne pas étendre 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();
}

}

Enfin, dans votre manifeste, vous déclarez l'emballage en tant que votre agent de sauvegarde:

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

Étant donné que votre emballage contient les méthodes appropriées définies, vous ne rencontrerez pas un problème lorsque le gestionnaire de sauvegarde jette à un BackupAgent. Étant donné que les niveaux d'API inférieurs ne seront pas un BackupManager le code ne sera jamais obtenir appelé, de sorte que vous ne rencontrerez aucune exception d'exécution non plus.

Insted de simplement appeler BackupManager.dataChanged, vérifier si la classe existe d'abord.

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

Qu'en est-

    if (android.os.Build.VERSION.SDK_INT >= 8) 
    {
        BackupManager bm = new BackupManager(this);
        bm.dataChanged();
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top