RealmList serialization issues (Realm/Gson/Intent)

时间:2016-08-31 12:33:02

标签: java android serialization realm

I use Retrofit, Gson and Realm in my project. I have this class Examplethat need to be Serializable. Without Realm I'd write it like that :

public class Example implements Serializable {
    @SerializationName("users")
    private List<String> users

    //... getters and setters
}

Realm comes into play and Example becomes (note that getters and setters are this way for compatibility reasons) :

public class Example extends RealmObject implement Serializable {

    @SerializedName("users")
    private RealmList<RealmString> users;

    public ArrayList<String> getUsers() {
        ArrayList<String> array = new ArrayList<>();
        for (RealmString rs : users) {
            array.add(rs.getValue());
        }
        return array;
    }

    public void setUsers(ArrayList<String> users) {
        RealmList<RealmString> array = new RealmList<>();
        for (String rs : users) {
            array.add(new RealmString(rs));
        }
        this.users = array;
    }

}

with RealmString being :

public class RealmString extends RealmObject implements Serializable {

    private String val;

    //Constructors, getter and setter
}

and add a custom Gson type converter for it to be deserialized correctly :

public class RealmStringRealmListConverter implements JsonSerializer<RealmList<RealmString>>,
        JsonDeserializer<RealmList<RealmString>> {

    @Override
    public JsonElement serialize(RealmList<RealmString> src, Type typeOfSrc,
                                 JsonSerializationContext context) {
        JsonArray ja = new JsonArray();
        for (RealmString tag : src) {
            ja.add(tag.getValue());
        }
        return ja;
    }

    @Override
    public RealmList<RealmString> deserialize(JsonElement json, Type typeOfT,
                                              JsonDeserializationContext context)
            throws JsonParseException {
        RealmList<RealmString> tags = new RealmList<>();
        JsonArray ja = json.getAsJsonArray();
        for (JsonElement je : ja) {
            if (je.isJsonPrimitive()) {
                tags.add(new RealmString(je.getAsString()));
            }
        }
        return tags;
    }

}

Ok so now we're starting to feel that Realm is starting to have to big of an impact over our code. But that's a side problem, the main issue is that Example is no longer Serializable : RealmList isn't.

so I tried to make the RealmList transient and have its pendent List that I can annotate with @Ignore, and recreate the RealmList after serialization. But transient is not accepted by Realm.

Now I feel a bit stuck, Example is passed through intents in numerous parts of my code (it's a member of a lot of classes). I don't want to use an id and query it everywhere.

My question would be :

How can I change ̀ Example` in a way that allows me to do new Bundle().putSerializable("test", new Example()); without crash.

Thanks for helping !

3 个答案:

答案 0 :(得分:3)

Serializable无法与RealmList一起使用,但您可以使用Parceler library and implement Parcelable  包裹RealmObjects(注意:它会将它们变成非托管副本!)

@Parcel(implementations = { UserRealmProxy.class },
        value = Parcel.Serialization.BEAN,
        analyze = { User.class })
public class User extends RealmObject {
    // ...
}

compile "org.parceler:parceler-api:1.0.3"
apt "org.parceler:parceler:1.0.3"

parcel RealmList, use following code

/* Copyright 2016 Patrick Löwenstein
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

public class RealmListParcelConverter implements TypeRangeParcelConverter<RealmList<? extends RealmObject>, RealmList<? extends RealmObject>> {
  private static final int NULL = -1;

  @Override
  public void toParcel(RealmList<? extends RealmObject> input, Parcel parcel) {
    if (input == null) {
      parcel.writeInt(NULL);
    } else {
      parcel.writeInt(input.size());
      for (RealmObject item : input) {
        parcel.writeParcelable(Parcels.wrap(item), 0);
      }
    }
  }

  @Override
  public RealmList fromParcel(Parcel parcel) {
    int size = parcel.readInt();
    RealmList list = new RealmList();

    for (int i=0; i<size; i++) {
      Parcelable parcelable = parcel.readParcelable(getClass().getClassLoader());
      list.add((RealmObject) Parcels.unwrap(parcelable));
    }

    return list;
  }
}

答案 1 :(得分:0)

步骤1:

 Gson gson = new GsonBuilder()
   .setExclusionStrategies(new ExclusionStrategy() {
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getDeclaringClass().equals(RealmObject.class);
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
})
.create();

 intent.putExtra("userfrom",gson.toJson(obj));

步骤2:

        Gson gson = new GsonBuilder().create();

    user = gson.fromJson(getIntent().getStringExtra("userfrom"),User.class);

我用它来传递Intent传递数据,但是用于改造

答案 2 :(得分:0)

我制作了一个可以代替 SerializableRealmListRealmList。这样,列表可以通过 ObjectOutputStream 进行序列化。

class SerializableRealmList<E> : RealmList<E>(), Serializable {

    private fun readObject(inputStream: ObjectInputStream) {
        @Suppress("UNCHECKED_CAST")
        addAll(inputStream.readObject() as List<E>)
    }

    private fun writeObject(outputStream: ObjectOutputStream) {
        outputStream.writeObject(toList())
    }
}