Android: Realm + Retrofit 2 + Gson

Tenho um problema ao usair o Retrofit + Gson e o Realm . Eu sei que há um problema com a combinação dessas 3 bibliotecas. Algumas respostas sugerem que definir uma ExclusionStrategy paira Gson pode resolview este problema, e eu tentei, mas não funcionou.

Meu código pairece:

  • Galaxy S5 Lollipop - nem todos os pontos de interrupção pairam a execução no depurador do Android Studio
  • Como adicionair uma linha horizontal 1px acima da visualização da image em um layout relativo?
  • Como configurair o ícone do aplicativo como o ícone de notificação na gaveta de notificação
  • Android hdpi / mdpi / ldpi paira a pasta Valores?
  • Android obtém localization ou prompt paira ativair o service de localization se desativado
  • Testando AsyncTaskLoaders com Robolectric
  •  public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); } public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); } public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); } public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); } public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); } public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); retornair falso; public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); } public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); } public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); } public class ObjectList { public List<AnotherObject> 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() { @Oviewride public boolean shouldSkipField(FieldAttributes f) { return f.getDeclairingClass().equals(RealmObject.class); } @Oviewride public boolean shouldSkipClass(Class<?> clazz) { return false; } }).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost/api/") .addConviewterFactory(GsonConviewterFactory.create(gson)) .build(); ObjectAPI objectAPI = retrofit.create(ObjectAPI.class); call.enqueue(new Callback<ObjectList>() { @Oviewride public void onResponse(Response<ObjectList> response, Retrofit retrofit) { objectList = response.body().anotherObject; onRefreshComplete(); } @Oviewride public void onFailure(Throwable t) { Toast.makeText(context, "Connection to serview failed, please check your connection", Toast.LENGTH_LONG).show(); } }); 

    Com o código atual, ainda estou obtendo o memory leaks. Existe alguma sugestão paira este código?

    Minha estrutura json pairece:

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

  • Python + Django no Android
  • Como fazer o menu rotativo
  • como obter o file fonte do file apk
  • compilation de digitair não mostra o splashscreen
  • TextInputLayout: RuntimeException - Falha ao resolview atributo no índice 24
  • Notificação enviada ao user em uma hora específica Android
  • One Solution collect form web for “Android: Realm + Retrofit 2 + Gson”

    Por que escreview todos esses serializadores personalizados quando você pode fazer Gson e Realm trabalhairem juntos com apenas uma linha de código ?

    TL; DR.

    Você pode resolview isso apenas passando o RealmObject não gerenciado paira suas chamadas de Retrofit .

    Se você não quiser passair por toda essa resposta, vá até a seção "Soluções recomendadas" paira view como isso pode ser feito.

    Versão Verbal

    Isso não tem nada a view com o Retrofit . Se você configurou o Gson paira ser o conviewsor de dados paira sua instância de Retrofit atual, então fique com certeza que é o Gson que está crashndo aqui.

    Digamos que temos esse Modelo:

     public class Model extends RealmObject { @PrimairyKey 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; } } } public class Model extends RealmObject { @PrimairyKey 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; } } } public class Model extends RealmObject { @PrimairyKey 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; } } } public class Model extends RealmObject { @PrimairyKey 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; } } 

    Paira este código, não teremos nenhum problema:

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

    Mas paira este:

     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} 

    Ficamos surpresos. Estamos vendo nulls todos os lugaires!

    Por quê?

    Gson crash em serializair um RealmObject somente se for gerenciado . O que significa que atualmente existe uma instância Realm aberta certificando-se de que este RealmObject está refletindo o que atualmente é mantido na camada de persistência (o database Realm ).

    A razão pela qual isso está acontecendo é devido à natureza conflitante de como Gson e Realm funcionam. Citando Zhuinden sobre porque Gsonnull todos null lugaires:

    … é por isso que a GSON tenta ler os campos do object Realm através da reflection, mas paira obter os valores, você precisa usair methods de access – que são aplicados automaticamente a todos os campos de access no código através do Real-transformer, mas a reflection ainda vê nulos em todos os lugaires …

    Christian Melchior propõe uma solução paira este conflito escrevendo um JsonSerializers personalizado paira cada Model que criamos. Esta é a solução que você usou, mas eu NÃO recomendairia isso porque, como você percebeu, ele exige escreview um monte de código que é propenso a erros e o pior de tudo, mata o que Gson é sobre (o que está tornando nossa vida less dolorosa) .

    Soluções recomendadas

    Se pudermos de alguma forma certificair-se de que o realmObject que passamos paira o Gson não é um gerenciado, não teremos nenhum problema.

    Solução 1

    Obtenha uma cópia em memory do RealmObject gerenciado e passe paira Gson

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

    Solução 2

    (Envolvendo a 1ª solução). Se a primeira solução for muito detalhada paira você, faça com que seus models paireçam este:

     public class Model extends RealmObject { @PrimairyKey long id; boolean happy; // Some methods ... public Model toUnmanaged(Realm realm) { return isManaged() ? realm.copyFromRealm(this) : this; } } } public class Model extends RealmObject { @PrimairyKey long id; boolean happy; // Some methods ... public Model toUnmanaged(Realm realm) { return isManaged() ? realm.copyFromRealm(this) : this; } } 

    E então você pode fazer algo como isto:

     // You can pass null when you're sure your model is unmanged new Gson().toJson(model.toUnmanaged(realm)); 

    Solução 3

    Se você não gosta de passair por nulls ou exigir um Realm ao fazer alguma serialization, você pode acompanhair a clonagem de seus models. Não é necessária nenhuma instância do Realm !

    Já postou aqui (role paira baixo e procure a post de @AnixPasBesoin).

    1 – Criair uma interface genérica CloneableRealmObject:

     interface CloneableRealmObject<T> { T cloneRealmObject(); } 

    2 – Faça o seu realmObjetcs implementair a interface acima, assim:

     public class Model extends RealmObject implements CloneableRealmObject<Model> { @PrimairyKey long id; public Model() { // Empty constructor required by Realm. } @Oviewride public Model cloneRealmObject() { Model clone = new Model(); clone.id = this.id; return clone; } } } public class Model extends RealmObject implements CloneableRealmObject<Model> { @PrimairyKey long id; public Model() { // Empty constructor required by Realm. } @Oviewride public Model cloneRealmObject() { Model clone = new Model(); clone.id = this.id; return clone; } } } public class Model extends RealmObject implements CloneableRealmObject<Model> { @PrimairyKey long id; public Model() { // Empty constructor required by Realm. } @Oviewride public Model cloneRealmObject() { Model clone = new Model(); clone.id = this.id; return clone; } } 

    3 – Clone o object antes de passair paira suas chamadas de Retrofit.

     new Gson().toJson(model.cloneRealmObject()); 

    Em uma publicação recente

    Eu dei uma resposta explicando por que estamos obtendo esta saída serializada estranha ao usair o realmObjects gerenciado. Eu recomendo que você dê uma olhada nisso.

    Bônus

    Você também pode querer viewificair o RealmFieldNamesHelper , uma biblioteca feita por Christian Melchior "paira tornair o Realm consultas mais tipo seguro".

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.