web-dev-qa-db-ja.com

アクティビティの再起動間で複雑なオブジェクトを保持するにはどうすればよいですか?

シリアル化可能なJava Beanオブジェクトがあるとします。アクティビティがonDestroy()を意図的に通過するときに安全に保管したいとします(つまり、onSaveInstanceState()はnotと呼ばれます)。

データベースを作成してそれにオブジェクトを書き込む必要のない方法を探しています(主にa)AndroidのDB APIがひどいため、b)データベースがアプリケーションの更新を悪夢にするため、移行を適用するための適切なサポートがないため)。

オブジェクトをByteArrayOutputStreamにシリアル化し、base64でエンコードして、SharedPreferencesファイルに文字列として書き込むことを考えました。それともそれは遠すぎますか?

[〜#〜]更新[〜#〜]

おそらく、文字列へのシリアル化のアイデアはそれほど悪くはなかったのかもしれませんが、かなりうまくいくようです。これが私が今していることです:

    public static String objectToString(Serializable object) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
        new ObjectOutputStream(out).writeObject(object);
        byte[] data = out.toByteArray();
        out.close();

        out = new ByteArrayOutputStream();
        Base64OutputStream b64 = new Base64OutputStream(out);
        b64.write(data);
        b64.close();
        out.close();

        return new String(out.toByteArray());
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

public static Object stringToObject(String encodedObject) {
    try {
        return new ObjectInputStream(new Base64InputStream(
                new ByteArrayInputStream(encodedObject.getBytes()))).readObject();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

onDestroy()では、Base64文字列を設定ファイルに書き込むだけで、次のアクティビティの起動時に再度読み取るまで安全です。予想よりもはるかに高速で、Beanに大量のデータが含まれていない限り、かなりうまく機能します。さらに良いことに、DBスキーマを維持する必要はありません。

それでも、他の人がこれをどのように行うのか興味があります。

22
Matthias

データベースを作成してそれにオブジェクトを書き込む必要のない方法を探しています(主にa)AndroidのDB APIがひどいため、b)データベースがアプリケーションの更新を悪夢にするため、移行を適用するための適切なサポートがないため)。

AndroidのAPIは実際にはかなり合理的です。これは主に、SQLite APIの薄いラッパーであり、SQLiteAPIは組み込みデータベースにとってかなり合理的であるためです。さらに、Androidは、SQLiteOpenHelperを介して、アプリのアップグレード時にスキーマのアップグレードを支援します。

予想よりもはるかに高速で、Beanに大量のデータが含まれていない限り、かなりうまく機能します。

シリアル化で長期的な成功を収めている人々の話を聞いたよりも、シリアル化から逃げる開発者の方がはるかに多いと聞いています。ちょうど過去数日以内に、ここSO #Androidで、ルーツによって彼のアプリからシリアル化を取り除こうと必死に努力している誰かと交換しました。

さらに良いことに、DBスキーマを維持する必要はありません。

そうそう、そうです。アプリケーションを更新してクラスを変更すると、どうなると思いますか? bookkeeping を実行して、古いバージョンのクラスを新しいバージョンのクラスから逆シリアル化する方法を理解することは面倒であり、開発者がシリアル化を放棄する理由の1つです。また、SQLiteはトランザクションであるのに対し、シリアル化はトランザクションではないことを忘れないでください。

9
CommonsWare

また、Beanまたはアクティビティ状態をアン/マーシャリングするための優れたアプローチも探していました。アクティビティのonStoreInstanceState()とonRestoreInstanceState()がどれほど苦痛であるかは誰もが知っています。

私の活動は、状態をonPause()に格納し、オブジェクトの直接シリアル化を介してonCreate()ライフサイクルフックに復元するだけです。

あなたのように文字列を介したシリアル化はもちろん可能ですが、ビッグデータにはあまり適していないため、多くのオーバーヘッドが発生します。さらに、プリファレンスは実際にはデータではなくプリファレンスを保存するためにあります:)残念ながら、この目的で使用できるParcelable/Parcelは、永続ストレージに保存することをお勧めしません。

したがって、残っているのは単純なオブジェクトのシリアル化です-幸いなことにAndroid SDKにはすべての欠点と利点を備えたObjectInputStreamクラスとObjectOutputStreamクラスが実装されています-Android以外の場合と同じようにJava世界、単純:

ObjectOutputStream.writeObject(yourPojo)

私たちのために魔法をかけるでしょう(Serializableマーカーインターフェースを実装することを忘れないでください)

また、Context-ContextWrapper-Activityの次のAPIを調べることもできます。これらは、ローカルデータ(画像など)などをキャッシュするのに非常に便利です。

.getCacheDir()
.getDir()
.openFileInput()
.openFileOutput()

ハッピーハッキング:)

3
comeGetSome