6

我正在研究使用自Android 2.2以來可用的新備份API,但需要保持向後兼容性(確切爲1.5)。向後兼容BackupAgent

的文檔狀態:

備份服務,你必須使用的API僅適用於運行API等級8(安卓2.2)或更高版本的設備,所以你也應該設置你的安卓的minSdkVersion屬性「8」。但是,如果您在應用程序中實現了適當的向後兼容性,則可以爲運行API Level 8或更高級別的設備支持此功能,同時保持與舊設備的兼容性。

我確實築起了8級水平,並嘗試使用一個包裝類(反射)克服,如果你實現擴展一個不存在的類一類的應用程序將無法運行的問題。

以下是問題所在:由於我們自己並沒有實際調用BackupHelper類,因此我們無法事先檢查類是否確實存在。 (正如Android向後兼容性文檔中所述,使用checkAvailable()方法)。因此該類將被實例化並轉換爲BackupAgent。但由於我們使用反射,它實際上並沒有覆蓋BackupAgent並在請求備份在運行時發生異常:

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

這裏是我的方式,以向後兼容BackupAgenthttp://code.google.com/p/transdroid/source/browse/#svn/trunk/src/org/transdroid/service其中BackupAgent.java是'常規'BackupAgentHelper擴展類和BackupAgentHelperWrapper是基於反射的包裝類。

任何成功實施BackupAgent向後兼容?

+0

我相信有一說起今年的Barcamp在Droidcon這樣做。不記得這個人的名字,但值得有一個搜索。 – 2010-06-22 11:02:40

回答

7

我不明白你爲什麼會遇到這個問題。

我有同樣的問題:我想支持也支持1.5(API 3)的應用程序的備份。

創建我的BackupAgentHelper類沒有任何問題,因爲該類不會從我自己的代碼中調用,而是從BackupManager(即系統本身)中調用。所以我不需要把它包起來了,我不明白爲什麼你應該做的是:

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

但是,你想獲得一個備份運行,要做到這一點,你需要在BackupManager.dataChanged()調用只要您的數據發生變化,並且您想通知系統進行備份(使用您的BackupAgentBackupAgentHelper)。

你確實需要包裝那個類,因爲你從應用程序代碼中調用它。


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當您重新安裝應用程序應適當的備份和恢復。每次)

+0

看起來很有希望,我會試試看。 – 2010-10-18 14:32:53

+0

你是完全正確的:這個伎倆!備份代理可以是擴展BackupAgentHelper的常規類,它是dataChanged包裝的調用。因此,我們圍繞BackupManager做了一個包裝。我可以在http://code.google.com/p/transdroid/source/browse/trunk/src/org/transdroid/service/BackupManagerWrapper.java找到我的代碼 – 2010-11-05 19:54:13

+0

無效鏈接 - 將鏈接發佈到實時項目的風險code.google.com =( – 2011-12-16 18:32:32

1

您需要的minSDK版本設置爲以下:

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

和構建目標設定爲8 SDK(在Eclipse項目屬性」 .default.properties'):

# Project target. 
target=android-8 

現在調用SDK 8中添加的新東西,你必須使用反射:http://developer.android.com/resources/articles/backward-compatibility.html

+0

我可能還不夠清楚(我編輯了我的答案以明確說明),但那正是我所嘗試的。問題在於包裝類無法擴展BackupAgent(這不會對1.5進行編譯),而是由Android備份機制轉換爲BackupAgent。 – 2010-06-22 08:51:24

+0

好吧,我想你將能夠在java中使用反射來擴展一個類:http://stackoverflow.com/questions/1886785/how-do-i-extend-java-classes-by-reflection – Moss 2010-06-22 12:53:17

1

我遇到了同樣的問題,這就是我所做的工作。

您不用包裝器擴展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,所以代碼將永遠不會被調用,因此您也不會遇到任何運行時異常。

+0

感謝您的建議。這基本上是我自己做的。我的包裝也定義了所需的方法。 由於在仿真程序或真實設備上調試進程似乎無法與bmgr工具一起使用,因此很難確定何時無法工作。 我想我的包裝中有一個錯誤,因爲我錯過了正確的構造函數。希望它現在可以工作,但我很快會就此回覆。 – 2010-06-28 09:09:57

10

作爲替代方案,你可以只使用純反射交談備份管理器:

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類;它將永遠不會加載到v2.2之前的虛擬機上,所以不會有任何連接問題。

+0

一個很好的例子, Android with reflection。感謝您發佈此內容。 – Zulaxia 2011-06-17 16:40:14

0

Insted只是調用BackupManager.dataChanged,檢查該類是否先存在。

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

如何

if (android.os.Build.VERSION.SDK_INT >= 8) 
    { 
     BackupManager bm = new BackupManager(this); 
     bm.dataChanged(); 
    }