Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ChangeListener no longer triggered on a findFirstAsync, after delete #4360

Closed
palto-blubek opened this issue Mar 21, 2017 · 5 comments
Closed
Assignees
Labels
Milestone

Comments

@palto-blubek
Copy link

Goal

I have a single Token object, that I need to insert/update/delete and be notified every time this happens.
Here's what I do:

        mTokenObservable = database.getRealm().where(Token.class).findFirstAsync();
        mTokenObservable.addChangeListener((RealmChangeListener<Token>) element -> {
            if (element.isValid()) {
                setAccessToken(element.accessToken);
            } else {
                // The token has been deleted
                setAccessToken(null);
            }
        });
  • This work after the first insert, and also after updates.
  • This also works after the first delete.
  • But when I insert again after that, I am no longer called.
    Note: I confirmed by using Realm Browser that the insert really worked.

Expected Results

I should be called.

Actual Results

On insertion after the delete, the listener is not triggered

Steps & Code to Reproduce

FYI: If I change my mTokenObservable to a list and use findAll instead of findFirstAsync, this works.

Code Sample

See above.

Version of Realm and tooling

Realm version(s): 3.0.0

Realm sync feature enabled: no

Android Studio version: Android Studio 2.4 Preview 2 Build #AI-171.3804685, built on March 15, 2017

Which Android version and device: Emulator API 23

@Zhuinden
Copy link
Contributor

Zhuinden commented Mar 21, 2017

So what you're trying to accomplish is:

0.) insert item into Realm
1.) create async findFirstAsync() query and add RealmChangeListener
2.) delete item from Realm
3.) receive change notification with isValid() == false
4.) insert item into Realm
5.) expect RealmChangeListener to be called with isValid() == true because an object that satisfies query exists

(please note I am not an official Realm person)

This is probably due to some difference in semantics compared to a PendingRow (which represents the query to a particular Row as in an actual Object) versus a Collection/Results (which represents a list of Rows that satisfy the query).

It seems to me that findFirst() in this regard is a one-off operation, while findAll() is a "subscription to data and its changes".

You should probably switch to findAllAsync().

Just today I was thinking about how odd it is that findFirst() returns an actual Object though, instead of something like a Single<Object> that can have null value and be updated just like a Results.

@beeender
Copy link
Contributor

When findFirstAsync() returns the 1st time, it indicates the query returns, then the RealmObject returned by the findFirstAsync() becomes a valid RealmObject. The listener will be triggered when the object changes (however, there are false positive notifications will be fixed by #4331 ).

When the object gets deleted, the listener will be called the last time. After that, the listener won't be triggered anymore. This works as design.

So, you could:

  • Call findFirstAsync() again and add the listener on its results
  • Or, as @Zhuinden said, use findAllAsync(), that will always re-run the query when db changes. But remember, the findAllAsync() returns a RealmResults, the first element won't be the same object always -- it depends on your sorting condition.

We will add more javadoc about this.

@beeender beeender added the T-Doc label Mar 21, 2017
@beeender beeender added this to the 3.1 milestone Mar 21, 2017
@palto-blubek
Copy link
Author

Thanks for replying - seeing that we always have one (or zero) Token, we thought findFirst made more sense, but didn't expect this difference in behavior with the findAll API. We switched to use findAll and it works fine.

@palto-blubek
Copy link
Author

(Sorry, closed too fast / reopened, seeing you want to update the documentation)

@Zhuinden
Copy link
Contributor

Truth be told, me as an outsider, I'm honestly not sure when the findFirstAsync() API is useful at all 😄

Honestly I use findFirst() on background threads (for getting something by ID, for example), and findAllAsync() for UI thread and store RealmResults as field reference, and that's that.

findFirst() will make sense once the RealmObjectChangeListener comes in for field-level change listeners, but even then, findFirstAsync() will forever be kinda strange

beeender added a commit that referenced this issue Mar 23, 2017
@beeender beeender self-assigned this Mar 23, 2017
beeender added a commit that referenced this issue Mar 24, 2017
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 16, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

5 participants