4

App Engine から情報を簡単に取得できるクラウド エンドポイント モデルの作成に成功しました。ラウンドトリップを減らしてより高速なユーザー エクスペリエンスを提供するために、ローカル ストレージに保存したいインスタンスを 1 つ特定しました。

アプリの残りの部分では、次のようなオブジェクトの読み取りと書き込みに ObjectInputStream を使用しています。

FileInputStream fis = context.openFileInput("PRIVFILE");
ObjectInputStream ois = new ObjectInputStream(fis);
AppModelState s = (AppModelState) ois.readObject();

これには明らかに、すべてのデータ メンバーが Serializable インターフェイスを実装する必要があります。Model クラスは GenericJSON を拡張し、「シリアライズ可能」ではありません。

    public final class ModelClass extends GenericJson {}

モデルにマップするシリアル化可能なオブジェクトを手動で作成できます。ただし、属性の数が多いため、それは非常に素人のようです。

私が検討したもう 1 つの代替案は、単純に JSON 文字列をメンバーとして持ち、ModelClass をパラメーターとして受け入れるセッター/ゲッターを提供するシリアライズ可能なオブジェクト ラッパーを作成することでした。

class AppModelState implements Serializable {
   private String modelClassJSON;

   public ModelClass getModelClass() {
      // generate a new ModelClass from the JSON
   }

   public void setModelClass(ModelClass c) {
      // extract the JSON for storage
   }

   .....
}

もっと良い方法があるに違いないと感じています。これは何十回も解決されているはずですが、リソースが見つかりません。入力してください。

4

2 に答える 2

6

私はあなたがあなたの質問で言っているのとまったく同じことをしています。

Cloud Endpoints オブジェクトはネットワーク経由で送信するために既にシリアル化されているため、シリアル化してローカルに保存することもできます。追加のボーナスとして、Android 3.0 以降では、ライブラリをインポートする必要さえありません。ライブラリは既に存在します。例えば:

import com.google.api.client.extensions.android.json.AndroidJsonFactory;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonFactory;

private static final JsonFactory JSON_FACTORY = new AndroidJsonFactory();

public void putObject(String key, Object value) throws Exception {
    byte[] outputbytes = null;
    if (value instanceof GenericJson) {
        outputbytes = JSON_FACTORY.toByteArray(value);
    } else {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ObjectOutputStream objectstream = new ObjectOutputStream(output);
        objectstream.writeObject(value);
        objectstream.close();
        outputbytes = output.toByteArray();
    }

    // persist "outputbytes" ...
}

public <T> T getObject(String key, Class<T> outclass) throws Exception {
    // retrieve saved bytes...
    byte[] valuebytes = ...

    if (valuebytes[0] == '{' && valuebytes[1] == '"' && valuebytes[valuebytes.length-1] == '}') {
        // Looks like JSON...
        return JSON_FACTORY.fromString(new String(valuebytes, "UTF-8"), outclass);
    } else {
        ByteArrayInputStream input = new ByteArrayInputStream(valuebytes);
        ObjectInputStream objectstream = new ObjectInputStream(input);
        Object value = objectstream.readObject();
        objectstream.close();
        return outclass.cast(value);
    }
}

長い文字列をシリアル化する場合、デフォルトAndroidJsonFactory(Android v4.3 以降) は非常に遅いことに注意してください。JacksonFactoryパフォーマンスに問題がある場合は、代わりに新しいを作成してください。他のすべては同じままです。

更新: GenericJson オブジェクトのリストをシリアル化する場合は、それらのオブジェクトのリストを含む GenericJson オブジェクトを作成するだけです。例えば:

import com.google.api.client.json.GenericJson;
import com.google.api.client.util.Key;

public static class PersistantJson extends GenericJson {
    @Key public int one;
    @Key public String two;
}

public static class PersistantJsonList extends GenericJson {
    @Key public List<PersistantJson> list = new ArrayList<PersistantJson>();
}

PersistantJsonすべての(つまり、「クラウド エンドポイント クライアント ライブラリの生成」によって作成された一部のクラス) オブジェクトを変数の.list要素に追加し、PersistantJsonListその変数を に渡すことができるようになりましたputObject()。これには、リスト内のすべてのオブジェクトが同じクラスである必要があることに注意してください。これにより、逆シリアル化で型が何であるかがわかります (JSON シリアル化では型が記録されないため)。使用する場合List<Object>、読み戻されるのは でList<Map<String, Object>>あり、フィールドを手動で抽出する必要があります。

于 2013-11-24T20:52:01.150 に答える
1

Endpoints で使用されるクラスの標準的な Java シリアル化を行うと、うまく機能しないと思います。問題は、シリアル化がバイナリであり、HTTP 通信が文字列であることです。

エンドポイントを使用するのではなく、自分で HTTP 通信を行っていた場合、同じ問題が発生すると思います。オブジェクトを送信するには、オブジェクトをシリアル化 (文字列メンバーをバイナリに変換) してから、バイナリを文字列に戻す必要があります。

したがって、使用しているデータの量が多すぎない場合は、オブジェクトを JSON として保存するのがおそらく最も簡単でしょう。

于 2013-03-11T02:30:04.593 に答える