realm / realm-java

Realm is a mobile database: a replacement for SQLite & ORMs
http://realm.io
Apache License 2.0
11.46k stars 1.75k forks source link

Commit not visible to other realms untill restart of the application #745

Closed dobby closed 9 years ago

dobby commented 9 years ago

When performing a realm.commitTransaction(); inside a thread the realm is not updated until the application is restarted. So the changes are persisted but not visible in my application when i query them from the main ui thread. This bug was not present in the previous version 0.75.

Example:

 new Thread(new Runnable() {
            public void run() {
               Realm realm =  Realm.getInstance(context);
               realm.beginTransaction();
               AnyRealmObject obj = realm.createObject(AnyRealmObject.class);
               realm.commitTransaction();

              realm.close();
            }
        }).start();

This code sent a onChange event in version (0.75) in my ui thread but doesn't do this any more. When deleting an object in a thread the onChange event is called.

cmelchior commented 9 years ago

Hi @dobby I tried to reproduce your code and couldn't. I tried using the below activity. Does your code differ from that?

public class ExampleActivity extends Activity {

    private Realm realm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_realm_basic_example);

        realm = Realm.getInstance(this);
        realm.addChangeListener(new RealmChangeListener() {
            @Override
            public void onChange() {
                int size = realm.allObjects(Cat.class).size();
                Log.e("REALM", "" + size);
            }
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                Realm realm = Realm.getInstance(getBaseContext());
                realm.beginTransaction();
                realm.createObject(Cat.class);
                realm.commitTransaction();
                realm.close();

            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        realm.close();
    }
}
denley commented 9 years ago

I've just run into the same issue. After a bit of head-scratching I've managed to isolate the cause a little more.

If you have just a single a Realm on the main thread with a change listener attached, then it works fine. The problem occurs after you create a second Realm on the main thread, and then close it. The first realm stops receiving change events.

Run the following as an example (adapted form @cmelchior 's code above). I have noticed that the log output does not occur with this code:

public class ExampleActivity extends Activity {

    private Realm realm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_realm_basic_example);

        realm = Realm.getInstance(this);
        realm.addChangeListener(new RealmChangeListener() {
            @Override
            public void onChange() {
                int size = realm.allObjects(Cat.class).size();
                Log.e("REALM", "" + size);
            }
        });

        final Realm anotherRealmOnTheMainThread = Realm.getInstance(this);
        anotherRealmOnTheMainThread.close();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Realm realm = Realm.getInstance(getBaseContext());
                realm.beginTransaction();
                realm.createObject(Cat.class);
                realm.commitTransaction();
                realm.close();

            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        realm.close();
    }
}
denley commented 9 years ago

I think that the issue could be fixed pretty easily. The problem is in these few lines in the Realm.close method: https://github.com/realm/realm-java/blob/master/realm/src/main/java/io/realm/Realm.java#L198-L200

The Realm's handler is being removed even when there are still active references to the Realm object. Perhaps it's just as simple as changing it to the following:

if (handler != null && refCount <= 0){
    removeHandler(handler);
}

I'm not familiar enough with the code to know if this will have any other consequences, so I'm not confident enough to make a pull request. But this should point in the right direction at least.

dobby commented 9 years ago

Hi @denley

I am glad you reproduced the error because I tried the other day and could not recreate the problem in a small sample project.

cmelchior commented 9 years ago

@denley Thank you for the code. You are absolute correct. The handler was getting removed to soon. It has been fixed in this PR: https://github.com/realm/realm-java/pull/753

cmelchior commented 9 years ago

Fix has been merged into master. Thanks for the bug report.