後方互換のバックアページェント
-
28-09-2019 - |
質問
Android 2.2以降利用可能な新しいバックアップAPIの使用を検討していますが、後方互換性を維持する必要があります(正確には1.5まで)。
ドキュメントの状態:
使用するバックアップサービスとAPIは、APIレベル8(Android 2.2)以下を実行しているデバイスでのみ利用可能であるため、Android:MinsdKversion属性を「8」に設定する必要があります。ただし、アプリケーションに適切な後方互換性を実装すると、古いデバイスと互換性がある間、APIレベル8以下を実行しているデバイスのこの機能をサポートできます。
私は確かにレベル8に反対しています targetSdkVersion
レベル3で minSdkVersion
ラッパークラス(反射付き)を使用して、存在しないクラスを拡張するクラスを実装した場合、アプリケーションが実行されない問題を克服してみてください。
ここに問題があります:私たちは実際に電話をかけないので BackupHelper
自分自身をクラスすると、クラスが実際に存在するかどうかを事前にチェックすることはできません。 (Android Backwards互換性のドキュメントで説明されているように checkAvailable()
方法。)したがって、クラスはインスタンス化され、 BackupAgent
. 。しかし、反射を使用するため、実際にはバックアページェントをオーバーライドすることはなく、バックアップが要求されたときに例外が発生します。
java.lang.RuntimeException: Unable to create BackupAgent org.transdroid.service.BackupAgent: java.lang.ClassCastException: org.transdroid.service.BackupAgent
これが後方互換性に対する私のアプローチです BackupAgent
: http://code.google.com/p/transdroid/source/browse/#svn/trunk/src/org/transdroid/service backupagent.javaは「通常の」backupagenthelper-extendingクラスであり、backupagenthelperwrapperが反射ベースのラッパークラスです。
誰でも実装することに成功しました BackupAgent
後方互換性がありますか?
解決
なぜあなたがこの問題に遭遇したのかわかりません。
同じ問題があります。1.5(API 3)もサポートするアプリでバックアップをサポートしたいと思います。
私を作成することに問題はありません BackupAgentHelper
クラス、そのクラスは私自身のコードから決して呼ばれることはありませんが、 BackupManager
つまり、システム自体。したがって、私はそれを包む必要はありません、そして、なぜあなたがそれをするべきなのかわかりません:
public class MyBackupAgentHelper extends BackupAgentHelper {
@override onCreate()
{
\\do something usefull
}
ただし、バックアップを実行したい場合は、電話をかける必要があります。 BackupManager.dataChanged()
データが変更され、システムにバックアップするように通知したいときはいつでも(あなたの使用を使用して BackupAgent
また BackupAgentHelper
).
アプリケーションコードから電話するため、そのクラスをラップする必要があります。
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
実際のシステムをエミュレートするたびに、バックプロセスを開始すると、アプリを再インストールするときに適切にバックアップして復元する必要があります。
他のヒント
別の方法として、純粋な反射を使用してバックアップマネージャーと話すことができます。
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をポイント:v2.2クラスでbackupagentをまっすぐにします。 Pre-V2.2 VMにロードされることはないため、リンケージの問題はありません。
minsdkバージョンを次のように設定する必要があります。
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8"/>
ビルドターゲットをSDK 8に設定します(Eclipseのプロジェクトプロパティ '.Default.Properties'):
# Project target.
target=android-8
次に、SDK 8に追加された新しいものを呼び出すには、リフレクションを使用する必要があります。 http://developer.android.com/resources/articles/backward-compatibility.html
私は同じ問題に遭遇しましたが、これが私がそれを解決するためにしたことです。
ラッパーで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"
>
ラッパーには適切な方法が定義されているため、バックアップマネージャーがバックアページェントにキャストした場合、問題は発生しません。 APIレベルの低下にはバックアップマネージャーがないため、コードが呼び出されることはないため、実行時の例外も実行されません。
backupmanager.datachangedを呼び出すだけで、クラスが最初に存在するかどうかを確認します。
try {
Class.forName("android.app.backup.BackupManager");
BackupManager.dataChanged(context.getPackageName());
} catch (ClassNotFoundException e) {
}
どうですか
if (android.os.Build.VERSION.SDK_INT >= 8)
{
BackupManager bm = new BackupManager(this);
bm.dataChanged();
}