当前位置:  开发笔记 > 前端 > 正文

Android:Realm + Retrofit 2 + Gson

如何解决《Android:Realm+Retrofit2+Gson》经验,为你挑选了1个好方法。

使用Retrofit + GsonRealm时遇到问题.我知道这3个库的组合存在问题.一些答案表明,ExclusionStrategyGson设置一个可以解决这个问题,我试过但它没有用.

我的代码看起来像:

public class ObjectList {
    public List anotherObject;
 }

public class AnotherObject extends RealmObject {
    private String propA;
    public void setPropA(String propA){
       this.setPropA = propA
    }
    public String getPropA(){
       return propA
    }
}

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

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://localhost/api/")
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();
    ObjectAPI objectAPI = retrofit.create(ObjectAPI.class);
    call.enqueue(new Callback() {
        @Override
        public void onResponse(Response response, Retrofit retrofit) {
            objectList = response.body().anotherObject;
            onRefreshComplete();
        }

        @Override
        public void onFailure(Throwable t) {
            Toast.makeText(context, "Connection to server failed, please check your connection", Toast.LENGTH_LONG).show();
        }
    });

使用当前代码,我仍然会收到内存泄漏.这段代码有什么建议吗?

我的json结构看起来像:

{"anotherObject":[{"propA": "someValue"}]}

Anix PasBeso.. 13

为什么要编写所有这些自定义序列化程序,以便让GsonRealm只与一行代码一起工作?

TL; DR.

你可以通过将unmanaged传递RealmObjects给你的Retrofit调用来解决这个问题.

如果您不想完成所有这些答案,请跳至下面发布的"推荐解决方案"部分.

冗长的谈话(冗长的回答)

这与Retrofit无关.如果您已将Gson设置为当前Retrofit实例的数据转换器,那么您可以确定它是Gson失败的人.

假设我们有这个模型:

public class Model extends RealmObject {
    @PrimaryKey
    long id;
    boolean happy;

    public Model() {/* Required by both Realm and Gson*/}

    public Model(long id, boolean happy) {
        this.id = id;
        this.happy = happy;
    }

    public long getId() {
        return id;
    }

    public boolean isHappy() {
        return happy;
    }
}

对于此代码,我们没有任何问题:

Model unmanagedModel = new Model(5, true); // unmanagedModel
new Gson().toJson(unmanagedModel);   // {id : 5, happy : true}

但对于这个:

Realm realm = /*...*/;
Model managedModel = realm.copyToRealm(unmanagedModel);
new Gson().toJson(managedModel); // {id : 0, happy : false}

// We'll get the samething for this code
Model anotherManagedModel = realm.where(Model.class).equalTo("id",5).findFirst();
new Gson().toJson(anotherManagedModel); // {id : 0, happy : false}

我们会感到惊讶.我们nulls到处都看到了!

为什么?

RealmObject如果Gson托管的,那么Gson就无法序列化.这意味着当前有一个打开的Realm实例,确保它RealmObject反映了当前持久层(Realm数据库)中的内容.

之所以发生这种情况,是因为GsonRealm的工作方式存在冲突.引用Zhuinden为什么Gsonnull到处都看到了:

...这是因为GSON尝试通过反射读取Realm对象的字段,但是要获取值,您需要使用访问器方法 - 它们通过Realm-transformer自动应用于代码中的所有字段访问,但反射到处都看到空值...

Christian Melchior通过为每个创建者编写一个自定义来提出解决此冲突的方法.这是您使用过的解决方法,但我不推荐它.正如你已经意识到的那样,它需要编写大量易于出错的代码,而最糟糕的是,它会杀死所谓的内容(这会让我们的生活变得更加痛苦).JsonSerializersModelGson

推荐解决方案

如果我们能以某种方式确保realmObject我们传递给Gson不是managed一个,我们将避免这种冲突.

解决方案1

获取托管RealmObject的内存副本并将其传递给Gson

new Gson().toJson(realm.copyFromRealm(managedModel));

解决方案2

(包装第一个解决方案).如果第一个解决方案对你来说太冗长,那么让你的模型看起来像这样:

public class Model extends RealmObject {
    @PrimaryKey
    long id;
    boolean happy;

    // Some methods ...

    public Model toUnmanaged() {
        return isManaged() ? getRealm().copyFromRealm(this) : this;
    }
}

然后,你可以做这样的事情:

// always convert toUnmanaged when serializing
new Gson().toJson(model.toUnmanaged());

解决方案3

如果(像我一样)你认为通过它managed或者realmObjects在进行某些序列化时要求它是丑陋的,那么你可以去克隆你的模型.不需要RealmObjects实例!

已经发布在这里(向下滚动并查找@ AnixPasBesoin的帖子).

1 - 创建一个通用接口CloneableRealmObject:

interface CloneableRealmObject {
    T cloneRealmObject();
}

2 - 让你的realmObjetcs实现上面的界面,如下所示:

public class Model extends RealmObject implements CloneableRealmObject {
    @PrimaryKey
    long id;

    public Model() {
        // Empty constructor required by Realm.
    }

    @Override
    public Model cloneRealmObject() {
        Model clone = new Model();
        clone.id = this.id;
        return clone;
    }
}

3 - 在传递给您的Retrofit调用之前克隆对象.

new Gson().toJson(model.cloneRealmObject());
在最近的一篇文章中

我给出了一个答案,解释了为什么我们在使用时得到这个奇怪的序列化输出nulls RealmObject.我建议你看一下.

奖金

您可能还想检查RealmFieldNamesHelper,这是一个由Christian Melchior 创建的库,"使Realm查询更安全".



1> Anix PasBeso..:

为什么要编写所有这些自定义序列化程序,以便让GsonRealm只与一行代码一起工作?

TL; DR.

你可以通过将unmanaged传递RealmObjects给你的Retrofit调用来解决这个问题.

如果您不想完成所有这些答案,请跳至下面发布的"推荐解决方案"部分.

冗长的谈话(冗长的回答)

这与Retrofit无关.如果您已将Gson设置为当前Retrofit实例的数据转换器,那么您可以确定它是Gson失败的人.

假设我们有这个模型:

public class Model extends RealmObject {
    @PrimaryKey
    long id;
    boolean happy;

    public Model() {/* Required by both Realm and Gson*/}

    public Model(long id, boolean happy) {
        this.id = id;
        this.happy = happy;
    }

    public long getId() {
        return id;
    }

    public boolean isHappy() {
        return happy;
    }
}

对于此代码,我们没有任何问题:

Model unmanagedModel = new Model(5, true); // unmanagedModel
new Gson().toJson(unmanagedModel);   // {id : 5, happy : true}

但对于这个:

Realm realm = /*...*/;
Model managedModel = realm.copyToRealm(unmanagedModel);
new Gson().toJson(managedModel); // {id : 0, happy : false}

// We'll get the samething for this code
Model anotherManagedModel = realm.where(Model.class).equalTo("id",5).findFirst();
new Gson().toJson(anotherManagedModel); // {id : 0, happy : false}

我们会感到惊讶.我们nulls到处都看到了!

为什么?

RealmObject如果Gson托管的,那么Gson就无法序列化.这意味着当前有一个打开的Realm实例,确保它RealmObject反映了当前持久层(Realm数据库)中的内容.

之所以发生这种情况,是因为GsonRealm的工作方式存在冲突.引用Zhuinden为什么Gsonnull到处都看到了:

...这是因为GSON尝试通过反射读取Realm对象的字段,但是要获取值,您需要使用访问器方法 - 它们通过Realm-transformer自动应用于代码中的所有字段访问,但反射到处都看到空值...

Christian Melchior通过为每个创建者编写一个自定义来提出解决此冲突的方法.这是您使用过的解决方法,但我不推荐它.正如你已经意识到的那样,它需要编写大量易于出错的代码,而最糟糕的是,它会杀死所谓的内容(这会让我们的生活变得更加痛苦).JsonSerializersModelGson

推荐解决方案

如果我们能以某种方式确保realmObject我们传递给Gson不是managed一个,我们将避免这种冲突.

解决方案1

获取托管RealmObject的内存副本并将其传递给Gson

new Gson().toJson(realm.copyFromRealm(managedModel));

解决方案2

(包装第一个解决方案).如果第一个解决方案对你来说太冗长,那么让你的模型看起来像这样:

public class Model extends RealmObject {
    @PrimaryKey
    long id;
    boolean happy;

    // Some methods ...

    public Model toUnmanaged() {
        return isManaged() ? getRealm().copyFromRealm(this) : this;
    }
}

然后,你可以做这样的事情:

// always convert toUnmanaged when serializing
new Gson().toJson(model.toUnmanaged());

解决方案3

如果(像我一样)你认为通过它managed或者realmObjects在进行某些序列化时要求它是丑陋的,那么你可以去克隆你的模型.不需要RealmObjects实例!

已经发布在这里(向下滚动并查找@ AnixPasBesoin的帖子).

1 - 创建一个通用接口CloneableRealmObject:

interface CloneableRealmObject {
    T cloneRealmObject();
}

2 - 让你的realmObjetcs实现上面的界面,如下所示:

public class Model extends RealmObject implements CloneableRealmObject {
    @PrimaryKey
    long id;

    public Model() {
        // Empty constructor required by Realm.
    }

    @Override
    public Model cloneRealmObject() {
        Model clone = new Model();
        clone.id = this.id;
        return clone;
    }
}

3 - 在传递给您的Retrofit调用之前克隆对象.

new Gson().toJson(model.cloneRealmObject());
在最近的一篇文章中

我给出了一个答案,解释了为什么我们在使用时得到这个奇怪的序列化输出nulls RealmObject.我建议你看一下.

奖金

您可能还想检查RealmFieldNamesHelper,这是一个由Christian Melchior 创建的库,"使Realm查询更安全".

推荐阅读
mobiledu2402852413
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有