2015-12-11 28 views
10

Tôi có một vấn đề khi sử dụng Retrofit + GsonRealm. Tôi biết rằng có một vấn đề với sự kết hợp của 3 thư viện này. Một số câu trả lời gợi ý rằng việc đặt một ExclusionStrategy cho Gson có thể giải quyết vấn đề này và tôi đã thử nó nhưng nó không hoạt động.Android: Realm + Retrofit 2 + Gson

Mã của tôi trông giống như:

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() { 
     @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<ObjectList>() { 
     @Override 
     public void onResponse(Response<ObjectList> 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(); 
     } 
    }); 

Với mã hiện tại, tôi vẫn nhận được rò rỉ bộ nhớ. Có đề xuất nào cho mã này không?

cấu trúc json của tôi trông giống như:

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

Không rõ bạn đang gặp phải vấn đề gì? Rò rỉ bộ nhớ nào? –

+0

Hwo bạn có nhận được 'response.body(). AnotherObject;'? Bạn nên sử dụng 'response.body(). Get (0 ..);'? –

+0

Cảm ơn tất cả các bạn, bây giờ vấn đề đã biến mất, tôi chỉ cần thêm phân đoạn loại trừ vào tất cả cá thể gson của tôi. – cana

Trả lời

12

Tại sao viết tất cả những serializers tùy chỉnh khi bạn có thể làm GsonRealm làm việc cùng nhau chỉ với một dòng mã?

TL; DR.

Bạn chỉ có thể giải quyết vấn đề này bằng cách chuyển không được quản lý RealmObjects sang số Trang bị thêm cuộc gọi của bạn.

Nếu bạn không muốn xem hết câu trả lời này, hãy chuyển đến phần "Giải pháp được đề xuất" được đăng bên dưới.

dài talk (câu trả lời dài dòng)

này không có gì để làm với Retrofit. Nếu bạn đã đặt Gson làm công cụ chuyển đổi dữ liệu sang phiên bản Trang bị thêm hiện tại của mình, thì bạn có thể chắc chắn rằng đó là Gson những người không thành công.

Giả sử chúng ta có mẫu này:

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

Đối với mã này, chúng tôi sẽ không có vấn đề:

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

Nhưng đối với cái này:

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} 

Chúng tôi sẽ ngạc nhiên. Chúng tôi đang xem nulls ở khắp mọi nơi !.

Tại sao?

Gson thất bại serializing một RealmObject chỉ nếu đó là một quản lý một.Điều này có nghĩa là hiện tại có một phiên bản Realm mở được đảm bảo rằng RealmObject này phản ánh những gì hiện đang được giữ trong lớp kiên trì (cơ sở dữ liệu Realm).

Lý do tại sao điều này xảy ra là do bản chất mâu thuẫn như thế nào cả GsonRealm làm việc. Trích dẫn Zhuinden về việc tại sao Gson thấy null ở khắp mọi nơi:

... đó là bởi vì GSON cố gắng đọc các lĩnh vực của đối tượng Realm thông qua phản ánh, nhưng để có được những giá trị, bạn cần phải sử dụng phương pháp accessor - được tự động áp dụng cho tất cả các truy cập lĩnh vực trong mã qua Realm-biến áp, nhưng phản ánh vẫn thấy null ở khắp mọi nơi ...

Christian Melchior đề xuất một workaround t xung đột của anh ấy bằng cách viết một tuỳ chỉnh JsonSerializers cho mọi ảnh được tạo Model. Đây là giải pháp thay thế bạn đã sử dụng, nhưng Tôi KHÔNG khuyến nghị sử dụng nó. Như bạn đã nhận ra, nó yêu cầu viết nhiều mãlỗi dễ bị và điều tồi tệ nhất, giết chết những gì Gson là khoảng (điều này làm cho cuộc sống của chúng ta bớt đau).

giải pháp khuyến nghị

Nếu chúng ta bằng cách nào đó có thể đảm bảo realmObject chúng tôi vượt qua để Gson không phải là một managed một, chúng tôi sẽ tránh xung đột này.

Giải pháp 1

Nhận một bản sao trong bộ nhớ của RealmObject quản lý và vượt qua nó để Gson

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

Giải pháp 2

(Bao bì các giải pháp 1). Nếu giải pháp 1 là quá tiết cho bạn, làm cho mô hình của bạn trông như thế này:

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

    // Some methods ... 

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

Và sau đó, bạn có thể làm một cái gì đó như thế này:

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

Giải pháp 3

Nếu (như tôi) bạn nghĩ rằng nó làm cho nó xấu xí để vượt qua nulls hoặc để yêu cầu một Realm khi làm một số serialization, sau đó bạn có thể đi với nhân bản mô hình của bạn. Không cần số Realm!

Đã được đăng here (cuộn xuống và tìm bài đăng của @ AnixPasBesoin).

1 - Tạo một giao diện CloneableRealmObject generic:

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

2 - Thực hiện realmObjetcs của bạn thực hiện các giao diện ở trên như sau:

public class Model extends RealmObject implements CloneableRealmObject<Model> { 
    @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 - Clone đối tượng trước khi đi qua các cuộc gọi Retrofit của bạn.

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

Trong một bài viết gần đây

Tôi đưa một answer giải thích lý do tại sao chúng tôi đang nhận được đầu ra tuần tự kỳ lạ này khi sử dụng managedrealmObjects. Tôi khuyên bạn hãy xem nó.

Bonus

Bạn cũng có thể muốn kiểm tra RealmFieldNamesHelper, thư viện do Christian Melchior "để làm cho Realm truy vấn loại hơn an toàn".

+0

Trang bị thêm không sử dụng Gson theo mặc định. Bạn phải đặt bộ chuyển đổi dữ liệu một cách rõ ràng. –

+0

@ cricket_007 bạn nói đúng. Tôi sẽ chỉnh sửa câu hỏi của mình. Nhưng, bằng cách nào đó, Gson là công cụ chuyển đổi dữ liệu được sử dụng nhiều nhất. – AnixPasBesoin

+0

Bởi vì tài liệu tối thiểu chỉ cho rằng đó là phiên bản sao chép-dán của cách sử dụng trang bị thêm. Một số người sử dụng nó với Jackson –

Các vấn đề liên quan