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