Reputation: 2982
I have an issue with realm. I receive a custom object from an API. I assign this object to a POJO object using retrofit. Within this object I have an ArrayList of the ToDoItem
object which extends RealmObject
.
I receive the data correctly with all attributes, everything gets correctly assigned. I run it through my synchronization algorithm and save it to realm in a writing transaction. But when retrieving the data after realm.commit();
the attributes of the objects are all 0
or null
.
The method isManaged()
is always false, even after the writing transaction, which I don't understand because in the official documentation is states that a POJO can be converted to a managed object using the copyToRealm
method.
I already tried a number of things: creating the GetItemResponseClass as RealmObject, but not possible since it has to extend JSONObject to correctly receive the data from the API. I also tried to write the whole list directly to realm but the result was the same.
As a side note, it can be that my method syncPendingLists
has some logic errors, but I couldn't debug it yet, since the attributes were always o and null. Thanks for any help.
Here my code from the Activity:
public class MainActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().name("myrealm.realm").build();
Realm.setDefaultConfiguration(config);
realm = Realm.getDefaultInstance();
RealmResults<Counter> counterList = realm.where(Counter.class).findAll();
//setting up counterObject
if (counterList.isEmpty()) {
counterObject = new Counter();
COUNTER = counterObject.getCounter();
} else {
counterObject = counterList.get(0);
COUNTER = counterObject.getCounter();
}
initializeLists();
//Adding the Fragment
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container, new DoneListFragment(), "DoneListFragment");
ft.add(R.id.fragment_container, new PendingListFragment(), "PendingListFragment");
ft.commit();
RetrofitClient retrofitClient = new RetrofitClient();
Retrofit retrofit = retrofitClient.getClient();
mAPIInterface = retrofit.create(ToDoistAPIInterface.class);
}
public void getRemoteItems() {
final ArrayList<ToDoItem> onlineItems = new ArrayList<ToDoItem>();
JSONArray array = new JSONArray();
array.put("items");
String auxMessage = array.toString();
mAPIInterface.getItems(RetrofitClient.TOKEN, "*", auxMessage).enqueue(new Callback<GetItemsResponseClass>() {
@Override
public void onResponse(Call<GetItemsResponseClass> call, Response<GetItemsResponseClass> response) {
GetItemsResponseClass itemsResponseClass = new GetItemsResponseClass();
itemsResponseClass = response.body();
remoteItemsList = itemsResponseClass.getItems();
boolean test = remoteItemsList.get(0).isManaged(); //returns false
boolean test1 = remoteItemsList.get(0).isValid(); //returns true refers to singleton RealmObject
syncPendingLists(pendingItemList, remoteItemsList);
}
@Override
public void onFailure(Call<GetItemsResponseClass> call, Throwable t) {
Snackbar.make(floatingButton, "Ups - Couldn't sync items, next time, I promise", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
private void initializeLists() {
RealmResults<ToDoItem> realmToDoItemPendingList = realm.where(ToDoItem.class).equalTo("checkedOffline", false).findAll();
initializingArrayListFromDB(realmToDoItemPendingList, pendingItemList);
RealmResults<ToDoItem> realmToDoItemDoneList = realm.where(ToDoItem.class).equalTo("checkedOffline", true).findAll();
initializingArrayListFromDB(realmToDoItemDoneList, doneItemList);
}
private void initializingArrayListFromDB(RealmResults<ToDoItem> realmToDoItemPendingList, ArrayList<ToDoItem> arrayList) {
int h;
for (h = 0; h < realmToDoItemPendingList.size(); h++) {
arrayList.add(realmToDoItemPendingList.get(h));
}
}
public void syncPendingLists(ArrayList<ToDoItem> offlinePendingList, ArrayList<ToDoItem> onlinePendingList) {
//is my sync algorithm, the important part is the for loop at the end of this method
boolean hasMatch = false;
boolean itemChanged = false;
Date offlineDate = null;
Date onlineDate = null;
if (!offlinePendingList.isEmpty()) {
for (ToDoItem item1 : offlinePendingList) {
if (item1.getId() < 10000) {
try {
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
for (int i = 0; i < onlinePendingList.size(); i++) {
if (item1.getId() == onlinePendingList.get(i).getId()) {
hasMatch = true;
onlinePendingList.remove(onlinePendingList.get(i));
//Compare Fields
if (!item1.getContent().equals(onlinePendingList.get(i).getContent())) {
itemChanged = true;
}
if (item1.getPriority() != onlinePendingList.get(i).getPriority()) {
itemChanged = true;
}
if (!item1.getDate_string().equals(onlinePendingList.get(i).getDate_string())) {
itemChanged = true;
}
if (itemChanged == true) {
//Format edit dates to date
DateFormat format = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
try {
offlineDate = format.parse(item1.getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
try {
onlineDate = format.parse(onlinePendingList.get(i).getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
//compare dates to see which was last edited
if (offlineDate.compareTo(onlineDate) > 0) {
try {
deleteRemoteItem(onlinePendingList.get(i), "item_delete");
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else if (offlineDate.compareTo(onlineDate) < 0) {
addOrUpdateToDB(item1);
}
}
}
if (!hasMatch) {
deleteObjectFromDB(item1);
}
}
}
}
}
for (ToDoItem onlineItem1 : onlinePendingList) {
boolean isManaged1 = onlineItem1.isManaged(); //returns false, which is ok since it is not yet in the realm db
onlineItem1.setLocalId(counterObject.getCounter());
addOrUpdateToDB(onlineItem1);
boolean asdf = onlineItem1.isManaged(); //it returns false, but it should return true
incrementCounter(counterObject);
}
initializeLists();
getPendingListFragment().refreshFragment();
}
private void addOrUpdateToDB(ToDoItem newItem) {
boolean test2= newItem.isManaged(); //returns false
realm.beginTransaction();
realm.copyToRealmOrUpdate(newItem);
//realm.copyToRealm(newItem); //I tried this method as well, but no difference
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and here is the problem, it should return true, shouldn't it?
assignValuesToToDoItem(itemWithValues, newItem);
saveCounterToDB(counterObject);
}
}
Here my class code of ToDoItem:
public class ToDoItem extends RealmObject implements Parcelable {
public static final Creator<ToDoItem> CREATOR = new Creator<ToDoItem>() {
@Override
public ToDoItem createFromParcel(Parcel in) {
return new ToDoItem(in);
}
@Override
public ToDoItem[] newArray(int size) {
return new ToDoItem[size];
}
};
@PrimaryKey
private long localId;
private String content;
private boolean checkedOffline = false;
private int priority;
private String date_string;
private String temp_id;
private long id;
private String date_added;
public ToDoItem(String name) {
this.content = name;
}
public ToDoItem() {
}
protected ToDoItem(Parcel in) {
localId = in.readLong();
content = in.readString();
checkedOffline = in.readByte() != 0;
priority = in.readInt();
date_string = in.readString();
temp_id = in.readString();
id = in.readLong();
date_added=in.readString();
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean isCheckedOffline() {
return checkedOffline;
}
public void setCheckedOffline(boolean checkedOffline) {
this.checkedOffline = checkedOffline;
}
public Long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public void setRemote_id(Long remote_id) {
this.id = remote_id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isDone() {
return checkedOffline;
}
public String getDate_string() {
return date_string;
}
public void setDate_string(String date_string) {
this.date_string = date_string;
}
public long getLocalId() {
return this.localId;
}
public void setLocalId(long i) {
this.localId = i;
}
public String getTemp_id() {
return temp_id;
}
public void setTemp_id(String temp_id) {
this.temp_id = temp_id;
}
public String getDateAdded() {
return date_added;
}
public void setDateAdded(String dateAdded) {
this.date_added = dateAdded;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(localId);
dest.writeString(content);
dest.writeByte((byte) (checkedOffline ? 1 : 0));
dest.writeInt((priority));
dest.writeString(date_string);
dest.writeString(temp_id);
dest.writeLong(id);
dest.writeString(date_added);
}
@Override
public String toString() {
return "localId: " + localId + "; content: " + content;
}
}
And here the code for the GetItemsResponseClass:
public class GetItemsResponseClass extends JSONObject {
private String sync_token;
@SerializedName("temp_id_mapping")
private HashMap<String, Long> temp_id_mapping;
private boolean full_sync;
@SerializedName("items")
private ArrayList<ToDoItem> items;
public GetItemsResponseClass(){
}
public String getSync_token() {
return sync_token;
}
public void setSync_token(String sync_token) {
this.sync_token = sync_token;
}
public HashMap<String, Long> getTemp_id_mapping() {
return temp_id_mapping;
}
public void setTemp_id_mapping(HashMap<String, Long> temp_id_mapping) {
this.temp_id_mapping = temp_id_mapping;
}
public boolean isFull_sync() {
return full_sync;
}
public void setFull_sync(boolean full_sync) {
this.full_sync = full_sync;
}
public ArrayList<ToDoItem> getItems() {
return items;
}
public void setItems(ArrayList<ToDoItem> items) {
this.items = items;
}
}
EDIT: Apparently it is a desired behavior that the object does not get saved with its attributes. Consequently to assign the values you have to use getters and setters. I added the following method, however even when debugging with a watch, as stated in the official documentation the values do not get assigned:
private void assignValuesToToDoItem(ToDoItem itemWithValues, ToDoItem newItem) {
realm.beginTransaction();
newItem.setContent(itemWithValues.getContent()); //the content variable stays null
newItem.setCheckedOffline(itemWithValues.isDone()); //stays false
newItem.setPriority(itemWithValues.getPriority());
newItem.setDate_string(itemWithValues.getDate_string());
newItem.setTemp_id(itemWithValues.getTemp_id());
newItem.setId(itemWithValues.getId());
newItem.setDate_added(itemWithValues.getDate_added());
realm.commitTransaction();
}
I added this line assignValuesToToDoItem(itemWithValues, newItem);
in the main activity in the method private void addOrUpdateToDB(ToDoItem newItem) {...}
Same result...
Upvotes: 1
Views: 766
Reputation: 2982
I found out 2 very important things:
0
, false
or null
Upvotes: 3
Reputation: 81539
copyToRealm()
and copyToRealmOrUpdate()
returns the managed proxy as a return value of the function you're calling.
realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and it should return false
Should be
newItem = realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns true
Upvotes: 0