Domanda

Sto cercando di utilizzare la nuova API di backup che disponibile dal Android 2.2, ma necessità di mantenere la compatibilità all'indietro (a 1,5 per l'esattezza).

Lo stato docs:

  

Il servizio di backup e le API è necessario utilizzare sono disponibili solo su dispositivi che eseguono API livello 8 (Android 2.2) o superiore, così si dovrebbe anche impostare il vostro Android: l'attributo minSdkVersion a "8". Tuttavia, se si implementa una corretta compatibilità a ritroso nella propria applicazione, è possibile supportare questa funzionalità per i dispositivi che eseguono API livello 8 o superiore, pur rimanendo compatibile con i dispositivi più vecchi.

I effettivamente costruire contro il targetSdkVersion livello 8 con il livello 3 minSdkVersion e tenta di utilizzare una classe wrapper (con la riflessione) per superare il problema che l'applicazione non funzionerà se si implementa una classe che estende una classe non esistente.

Qui è il problema: dal momento che non facciamo le chiamate effettivi alla classe BackupHelper noi stessi, non possiamo controllare in anticipo se la classe esiste davvero. (Come è spiegato nella documentazione Android compatibilità all'indietro con un metodo checkAvailable().) La classe sarà quindi un'istanza e il cast a un BackupAgent. Ma dal momento che usiamo riflessione, che in realtà non ignorare BackupAgent e si verifica un'eccezione in fase di esecuzione quando viene richiesto il backup:

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

Ecco il mio approccio ad un BackupAgent retrocompatibile: http://code.google.com/p/transdroid/source/browse/#svn/trunk/src/org/transdroid/service dove il BackupAgent.java è il 'normale' BackupAgentHelper-estendendo classe ed BackupAgentHelperWrapper è la classe wrapper riflessione-based.

Chiunque successo nell'attuazione di una BackupAgent con compatibilità all'indietro?

È stato utile?

Soluzione

Non vedo il motivo per cui si esegue in questo problema.

Ho lo stesso problema:. Voglio a sostegno supporto con un'applicazione che supporta anche 1.5 (API 3)

Non c'è nessun problema nella creazione di mia classe BackupAgentHelper, dal momento che la classe non viene mai chiamato dal mio codice, ma dal BackupManager vale a dire il sistema stesso. Quindi non ho bisogno di avvolgerlo, e non vedo il motivo per cui si dovrebbe fare che:

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

Tuttavia, si vuole ottenere un'esecuzione di backup, per farlo è necessario chiamare il BackupManager.dataChanged() ogni volta che le modifiche ai dati e si desidera informare il sistema per il backup (usando il vostro BackupAgent o BackupAgentHelper).

Si ha bisogno di avvolgere quella classe, dal momento che si chiama da voi codice dell'applicazione.


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

}

È quindi chiamano dal codice quando si cambia una preferenza o di risparmiare un po 'di dati. Alcuni codice dal mio app:


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

Quindi, speriamo che questo funziona per voi!

(Se si chiama adb shell bmgr run ogni volta che si desidera emulare il sistema attuale ha avviato backupprocess dovrebbe correttamente backup e ripristino quando si reinstalla l'applicazione.)

Altri suggerimenti

In alternativa, si può semplicemente utilizzare puro riflesso per parlare con il 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'androide: BackupAgent dritto verso una classe v2.2; non sarà mai venga caricato su pre-v2.2 VM, quindi non ci sarà alcun problema di collegamento.

È necessario impostare la versione minSDK al seguente:

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

e impostando l'obiettivo build per SDK 8 (proprietà del progetto in Eclipse' .default.properties'):

# Project target.
target=android-8

Ora chiamare roba nuova aggiunta nel SDK 8 è necessario utilizzare riflessione: http://developer.android.com/resources/articles/backward-compatibility.html

Ho incontrato lo stesso problema ed ecco cosa ho fatto di lavorare fuori.

non si estendono BackupAgent con l'involucro, si estende con la classe avvolto. Quindi, fate la vostra reale classe di backup:

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

}

Va bene, e allora si fanno un wrapper come articolo compatibilità lo sviluppatore Android all'indietro detto di fare. Si noti che questa classe non estendere 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();
}

}

Infine, nella vostra manifesta, si dichiara l'involucro come il vostro agente di backup:

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

Dal momento che l'involucro ha i metodi propri definiti non incorrere in un problema quando il manager di backup l'inserisce in un BackupAgent. Dal momento che i livelli più bassi di API non avranno un BackupManager il codice non potrà mai ottenere chiamato, in modo da non incorrere in eventuali eccezioni runtime ci sia.

invece di limitarsi a chiamare BackupManager.dataChanged, verificare se la classe esiste prima.

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

Come su

    if (android.os.Build.VERSION.SDK_INT >= 8) 
    {
        BackupManager bm = new BackupManager(this);
        bm.dataChanged();
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top