【问题标题】:RealmList serialization issues (Realm/Gson/Intent)RealmList 序列化问题(Realm/Gson/Intent)
【发布时间】:2017-01-08 01:18:31
【问题描述】:

我在我的项目中使用 Retrofit、Gson 和 Realm。 我有这门课Example需要Serializable。如果没有 Realm,我会这样写:

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

    //... getters and setters
}

Realm 开始发挥作用,Example 变为(请注意,出于兼容性原因,getter 和 setter 采用这种方式):

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

}

RealmString 是:

public class RealmString extends RealmObject implements Serializable {

    private String val;

    //Constructors, getter and setter
}

并添加一个自定义的 Gson 类型转换器以使其正确反序列化:

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

}

好的,现在我们开始感觉到 Realm 开始对我们的代码产生很大的影响。但这是一个附带问题,主要问题是 Example 不再是 Serializable :RealmList 不是。

所以我尝试将 RealmList 设为瞬态并拥有可以使用 @Ignore 注释的挂起列表,并在序列化后重新创建 RealmList。但是 Realm 不接受瞬态。

现在我感觉有点卡住了,Example 在我的代码的许多部分(它是很多类的成员)中通过意图传递。我不想使用 id 到处查询。

我的问题是:

如何更改 ̀ Example` 以使我能够在不崩溃的情况下执行 new Bundle().putSerializable("test", new Example());

感谢您的帮助!

【问题讨论】:

  • 您将无法通过意图传递任何领域对象。您必须传递一个 ID 和查询。正如你所说,你不想这样做。这就是它的工作原理。还;你有什么问题???
  • 好吧,我的问题是,如何做到这一点,使我的代码在Example 之外保持不变,即我可以在不崩溃的情况下执行new Bundle().putSerializable("example", new Example())。我更新了我的问题
  • 根据我的评论。只有不使用 Realm 才能做到这一点。 RealmObjects 是与 Realm DB 直接连接的活动对象。通常,您甚至不会真正访问您创建的对象,但在编译期间,Realm 插件会生成一个从您的对象扩展的代理对象,而您真正使用的是该代理对象。只需尝试登录Realm.getInstance().querySomething().getClass().getCanonicalName();,您就会发现它不再是您的实际对象了。
  • 但是我不能重写 Serializable 的序列化方法以按 id 存储然后查询它吗?我的主要问题是瞬态使领域不快乐
  • 所以如果我使用 Realm,我将永远无法通过 onSaveInstanceState 包存储对象来存储我的对象,我将不得不更改所有这些行为?

标签: java android serialization realm


【解决方案1】:

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

【讨论】:

  • 对于字符串列表,请考虑将它们存储到单个字符串字段中,而不是作为对象列表。
  • 我是领域的新手,我正在将领域集成为缓存数据库/本地数据库。我有用于常规使用和管理领域表示的模型。
  • 我正在考虑将数组列表添加为序列化字符串,这是一个好方法,因为我还没有找到任何领域列表的教程。
  • I am thinking of adding arraylists as serialized strings is it a good approach as I haven't found any tutorial for Realm lists. 对于原语是,对于 RealmObjects 否
  • 我通常有一个独立于 RealmObjects 的 API 模型。但我确实将 RealmObjects 直接用于 UI。如果有人有一个用于 Realm 查询评估的后台 Looper 线程,那么新的冻结 RealmResults 理论上是一个很好的解决方案。
【解决方案2】:

第一步:

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

第二步:

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

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

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

【讨论】:

    【解决方案3】:

    我创建了一个SerializableRealmList,可以用来代替RealmList。这样,列表可以被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())
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多