Summary of 'things to do' when upgrading from Java Realm DB 6 to 10?

We have a mobile app that is standardized on Java Realm database 6.0.2 and we are now in the planning phase for upgrading to the latest 10.x version (10.4.0 as of this writing).

We do not use the “sync” or “cloud” capabilities (we are just using Realm as a stand-alone embedded DB for our mobile app).

Outside of pouring through all the release notes and various change logs on GitHub, is there a summary somewhere akin to “so you are upgrading the stand-alone Realm Java DB from 6.x to 10.x, here is what you need to check for”?

I noticed from the notes in the 7.0 release for example, this comment under “Breaking Changes”:

All RxJava Flowables and Observables now return frozen objects instead of live objects.

I am not sure how to interpret this - we do use RxJava 3 in our app (RxAndroid actually), and we do use an instance of a Realm in the non-UI thread aspect to do various DB related activities.

We use RxJava Disposables all over the place to do background work. Here is an example of the pattern we employ:

    return Observable.fromCallable(() -> {
        try {

                Realm realm = InTouchDataMgr.get().getRealm();
                try {
                    <<DO ACTIVITY WITH REALM INSTANCE HERE>>
                    << RETURN PROPERLY CONFIGURED OBJ ARRAY>>
                } catch (Exception e) {
                    return new Object[] {-1, new ArrayList<DeviceInfo>()}; // Signals error happened
                } finally {
                    InTouchDataMgr.get().closeRealmSafely(realm);
                }

        } catch (Exception e) {
            return new Object[] {-1, new ArrayList<DeviceInfo>()}; // Signals error happened 
        }

    })
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribeWith(new DisposableObserver<Object>() {
        @Override
        public void onNext(Object o) {
            << DO ACTIVITY ON UI THREAD HERE>>
        }
        @Override
        public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
            << ERROR PROCESSING HERE>>
        }
        @Override
        public void onComplete() {
            << COMPLETION PROCESSING HERE>>
        }
    });

With the new default behavior as of 7.0.0 is this somehow changed under the covers unless we configure it per the release notes?

What other major “gotcha’s” might we run into?

Hello @Tad_Frysinger,

I acknowledge the age of the question and I hope you have been able to find an answer to this.

All RxJava Flowables and Observables now return frozen objects instead of live objects.

I am not sure how to interpret this - we do use RxJava 3 in our app (RxAndroid actually), and we do use an instance of a Realm in the non-UI thread aspect to do various DB related activities.

If you are not using our RxJava API, this should not affect you. This is tied to the observables and flowable that Realm Java creates.

For anyone else, trying to understand the concept, this is in reference to how the Realm database works internally or how threading works in Realm.

Live Objects

Realm works with Live Objects. You can operate on live objects in different threads, reading and writing to them, without worrying about what other threads are doing to those same objects. if you made an update in a transaction, the result will be visible on the other thread in real-time ( the updates will be scheduled as an event on the Looper, so Looper threads will be updated as soon as the event is processed)

The limitation here is that you cannot pass Live objects between threads. As Realm is based on zero-copy architecture, all objects are live and auto-updating. If they are passed across threads, it would lead to consistency issues as Realm does not have a locking mechanism and hence the speed with which it operates. If you need the same data on another thread, you need to query for that data on the other thread.

Frozen Objects

This concept in versions >= 7.0 allows Realm objects to share across threads. Frozen Realm objects act like immutable objects and do not change. You can freeze elements of your data and hand it over to other threads and operations without throwing an exception - this makes it easier to use Realm when working with platforms like RxJava & LiveData, RxSwift & Combine, and React.

Please check Dev-Hub article that explains more on how Frozen objects are used with Rx Flowables and Observables.

Use Frozen Objects with Caution

Realm is an MVCC database (Multiversion Concurrency Control). Realm does not follow a locking mechanism to maintain concurrency during read/write operations, it instead takes an alternative approach: each connected thread will see a snapshot of the data at a particular point in time.
The design choice is similar to Git with multiple branches but with a difference that with Realm, only a single writer can be operating at any time and will always work on the latest version - it cannot work on an earlier one.

When we use Frozen objects, there is a chance the database version will get pinned (if not closed properly or reference is not garbage collected) and this will cause the database file to grow. Holding on to multiple versions can lead to out-of-memory exceptions as well.

With the new version from 7/10, it is easier to pass objects between threads in a flow, but requires some effort to ensure that references to the old versions are not kept in the flow as this could cause the DB to grow”

I hope the provided information is helpful. Please feel free to reach out, if you have any questions.

Kind Regards,
Henna

1 Like