After running the following code I would have expected the realmList AND realmResults to be the same size after deleting a Realm object contained by both.
RealmList<Notification> realmList = getNotifications();
if (realmList != null && !realmList.isEmpty())
{
RealmQuery<Notification> query = realmList.where()
.notEqualTo("notificationType", Notification.TYPE_BOARD_MESSAGE)
.notEqualTo("notificationType", Notification.TYPE_DIRECT_MESSAGE);
RealmResults<Notification> realmResults = query.findAllSorted(Notification.PARAM_CREATED_AT, Sort.DESCENDING);
Log.d("REALM_TEST", "realmList before has " + realmList.size() + " items");
Log.d("REALM_TEST", "realmResults before has " + realmResults.size() + " items");
Notification firstNotification = realmList.first();
realm.beginTransaction();
firstNotification.deleteFromRealm();
realm.commitTransaction();
Log.d("REALM_TEST", "realmList after has " + realmList.size() + " items");
Log.d("REALM_TEST", "realmResults after has " + realmResults.size() + " items");
}
Output
D/REALM_TEST: realmList before has 5 items
D/REALM_TEST: realmResults before has 5 items
D/REALM_TEST: realmList after has 4 items
D/REALM_TEST: realmResults after has 5 items
The realmList updates correctly, removing the object real time. The realmResults however changes the object to "Invalid object" but does not remove it from the list. This results in unexpected behavior, especially when looping over the results.
Is there a better way to achieve this?
Thanks in advance for any help on this.
Realm version: 0.90.1
Android Studio version: 2.1.1
Android version: Android 6.0
Hi @joey-harward
This is intentional and was introduced in https://realm.io/news/realm-java-0.89.0/ as part of creating iterators that worked. Unfortunately there is no way to achieve both and we believed that having stable iterators were more important.
In your case there is a couple of things that can solve this.
1) Make a new query after you deleted the item for the list
2) Register a changelistener on the RealmResults, then you will notified when it changed
What is the use case where you needed this to work?
Hi @cmelchior! Thanks for the quick turn around!
I am using RealmResults for items in a RecyclerView adapter. During a 'swipe to delete' I would like to remove the Realm object at that index from the RealmResults. Since the object still exists in the RealmResults I can't call notifyItemRemoved (for the removal animation). I don't necessarily want to re-query because I may have a lot of items.
BTW, I did notice that this seems to work:
realm.beginTransaction();
//firstNotification.deleteFromRealm();
realmResults.deleteFromRealm(0);
realm.commitTransaction();
Yes, using the deleteFromRealm methods will remove them from both as well.
It is a bit unfortunate from our perspective that removing from RealmResults also remove from RealmList, while the opposite direction is not true, but right now it probably just a behavior we should document better.
The underlying reason is that a RealmResult is a collection of references into the data, while a RealmList is the actual data.
I'll just use that function for now. Thanks for the clarification!
After spending way too much time on this, I think it's best for me to go back to version 0.88.3. I have way too many RealmResults that need real time updating. Stable iterators are of no interest to me. I was using the for (int i = results.size() - 1; i >= 0; i--) technique for removals and everything was fine. One of the main things I love about Realm is the auto updating RealmList and RealmResults. It is a shame to see them go away :(
Maybe in a future release you can introduce a new class (RealTimeRealmResults or AutoRefreshRealmResults?) for people like me.
Sorry I only reopened this in the interest that it might get moved to a feature request :)
Well they do auto-update, but they (well, the realmresults, anyways) only do that on next execution of the looper thread, which is why you'd have to rely much more heavily on RealmChangeListener which can be added to a RealmResults<T> and not just a Realm.
In the meantime, I think you can use the following hack OUTSIDE OF A TRANSACTION in order to force the update of sync results, after you commit a transaction on the same thread you want to refresh on.
package io.realm;
public class RealmRefresh {
public static void refreshRealm(Realm realm) {
realm.checkIfValid();
if(realm.isInTransaction()) {
throw new IllegalStateException("Cannot refresh inside of a transaction.");
}
realm.sharedGroupManager.advanceRead();
realm.handlerController.refreshSynchronousTableViews();
}
}
And if you want to force a RealmResults to update even while in a transaction, then I think you can call
package io.realm;
public class RealmResultsHelper {
public static <T> void syncIfNeeded(RealmResults<T> realmResults) {
realmResults.syncIfNeeded();
}
}
I think that ought to work, with synchronous queries.
@joey-harward We talked about this internally and landed on that we prefer not adding any new class or method for this. 1) It would be complicated to document and 2) It will make it more difficult to reason about when change listeners are triggered.
The proper way of doing it should be calling deleteFromRealm() directly on the collection.
@cmelchior Does that mean that realm doesn't update itself, the only way we get notified that the data set has been changed is onChange?
@DanteAndroid Realm does update itself, that's when onChange() is called
also this behavior is a bit different since Realm 3.0.0
@Zhuinden Could you please elaborate a little bit? I'd like to update to 3.0
Results are immediately updated on local commits in 3.0.0
@DanteAndroid See https://realm.io/news/realm-java-3-0-collection-notifications/ about details of 3.0.0 changes.
@Zhuinden @beeender Thx for your guys' hard work! Realm is being better and better!
One more question: What is OrderedCollection?
RealmResults, RealmList or RealmSnapshotCollection
BTW we're back to the behavior of 0.88.3 in this terns of behavior with 3.1.2
Most helpful comment
After spending way too much time on this, I think it's best for me to go back to version 0.88.3. I have way too many RealmResults that need real time updating. Stable iterators are of no interest to me. I was using the
for (int i = results.size() - 1; i >= 0; i--)technique for removals and everything was fine. One of the main things I love about Realm is the auto updating RealmList and RealmResults. It is a shame to see them go away :(Maybe in a future release you can introduce a new class (RealTimeRealmResults or AutoRefreshRealmResults?) for people like me.
Sorry I only reopened this in the interest that it might get moved to a feature request :)