Realm IllegalStateException: accessing managed objects across threads during sync writes
0 reputation · 07 Jun 2020, 17:11 UTC
0 reputation · 07 Jun 2020, 17:11 UTC
I want to pass a managed Realm object from the main thread to a background worker so a heavy write transaction does not block the UI, while keeping the object usable for reading its current field values.
My understanding is that Realm managed objects are thread-confined: an instance obtained on one thread cannot be used on another, and doing so raises an IllegalStateException. The documented pattern seems to be re-querying by primary key on the destination thread, or copying values into an unmanaged object first. What I am unsure about is the exact boundary: does the confinement apply to the object instance only, or also to live collections and any Realm instance opened on the main thread? I also want to know whether frozen objects change this behavior in current Kotlin SDK versions (assume a recent 1.x release).
Realm instance itself, requiring a separate Realm.open() call per thread?To pass data from the main thread to a background worker without triggering an IllegalStateException, you have two primary options depending on whether you need a live object or a snapshot:
object.freeze(). Frozen objects are immutable snapshots that bypass thread confinement and can be passed directly to coroutines or background threads.Realm instance on that thread and re-query the object using that key.In Realm (Kotlin SDK 1.x), thread confinement is strict and applies to the following:
RealmResults and RealmList are also thread-confined. Passing a live list to a background worker will cause an IllegalStateException even if the originating Realm is closed.Realm instance itself is thread-confined. You cannot share a single Realm object across threads; each thread must call Realm.getInstance() or Realm.open() to obtain its own handle to the database.| Feature | Managed Object | Frozen Object |
|---|---|---|
| Thread Confined | Yes | No |
| Live Updates | Yes (Auto-updating) | No (Snapshot) |
| Modifiable | Yes (within transaction) | No (Immutable) |
val frozenUser = user.freeze().Verification: You can verify this by attempting to read a field from a managed object inside a Dispatchers.IO block; it will throw an IllegalStateException. Replacing that object with a frozen version will resolve the error.
Diagnostic Note: Please specify if you are using the legacy Realm Java SDK or the newer Realm Kotlin SDK (Atlas Device SDK), as the API for freezing and opening instances differs slightly between the two.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.