RealmChangeListener does not get called when Realm gets updated in NotificationListenerService
I can see two solutions to this, either use a looper thread (HandlerThread) with setAutoRefresh(true)
(and call setAutoRefresh(false)
before Looper.quit()
), or force a refresh for the Realm instance on the thread.
NOTE: This relies on package-internal methods. Beware.
In v 1.1.1 (and v1.2.0), - and any version before 3.0.0 - instead of the following line
// mRealm.waitForChange(); / mRealm.refresh();
You could force the update on the local thread through the HandlerController
associated with the Realm instance using package-internal stuff
package io.realm;
public class RealmRefresh {
public static void refreshRealm(Realm realm) {
Message message = Message.obtain();
message.what = HandlerControllerConstants.LOCAL_COMMIT;
realm.handlerController.handleMessage(message);
}
}
And then call
mRealm = Realm.getDefaultInstance();
RealmHelper.saveObj(myRealmObject, mRealm);
RealmRefresh.refreshRealm(mRealm);
mRealm.close();
Please note the change log's breaking changes though, because 0.89.0 changed iteration behavior, and results are no longer live during an active transaction; but from 3.0.0 they are again.
However, I must also note that if your NotificationListenerService
is running in a remote process, then the Realm instances won't be able to notify each other.
EDIT:
In Realm Java 3.0.0, the notification behavior was changed completely, and HandlerController
no longer exists.
Instead, the following should work:
package io.realm;
public class RealmRefresh {
public static void refreshRealm(Realm realm) {
realm.sharedRealm.refresh();
}
}
EDIT:
In Realm 3.2.+, this is all available with
realm.refresh();
Realm returning stale data
That's because
// This function simply stores a Realm model for all the data that has been uploaded to the server
private fun markDataAsUploaded(dataToUpload: List<CallLog>) {
realm = Realm.getDefaultInstance()
for (data in dataToUpload) {
realm.beginTransaction()
val callLogUploaded = realm.createObject(CallLogUploaded::class.java)
callLogUploaded.callDate = data.callDate
realm.commitTransaction()
}
}
This method has quite a few errors that I had written about a long time ago
The Realm instance is opened, but never closed
There is a new transaction per every element, rather than inserting all elements in a single transaction
If you don't close the Realm instance (each instance requires its own close()
call), then your Realm instance will never update unless you actually begin a transaction and do things inside the transaction.
You have three solutions:
1.) do your logic on the background thread inside a transaction, if there is nothing to be done, then cancel the transaction - queries made in transactions are never stale
2.) make sure the Realm instance is closed properly (although this is definitely a necessity on any non-autoupdating thread)
3.) a hacky solution is to call RealmRefresh.refreshRealm()
after getDefaultInstance()
according to my answer on Stack Overflow which relies on package-private API, but it works to solve this issue
Typically you need to open the Realm instance at the beginning of the thread, and close it at the end of the thread.
so, it's basically one big try(Realm realm = Realm.getDefaultInstance() { ... }
for onHandleIntent()
.
enqueue(new Callback() { @Override public void onSuccess(..) {...}
runs on the UI thread. To run it on the current thread, you should use call.execute()
.
instead of
for (data in dataToUpload) {
realm.beginTransaction()
val callLogUploaded = realm.createObject(CallLogUploaded::class.java)
callLogUploaded.callDate = data.callDate
realm.commitTransaction()
}
do
realm.beginTransaction()
for (data in dataToUpload) {
val callLogUploaded = realm.createObject(CallLogUploaded::class.java)
callLogUploaded.callDate = data.callDate
}
realm.commitTransaction()
In order to understand about version retention you can read https://medium.com/@Zhuinden/understanding-realm-version-retention-and-synchronization-9a513c2445bb .
Realm Inconsistent results
This answer applies if you use Schedulers.io()
:
Have you considered closing your Realm instance that you open on your thread pool?
Because if you don't close the Realm (which you don't), then you'll experience version retention and your Realm instance in your background thread will never get updated again.
Also consider refreshing the Realm after opening the instance using this force-refresh workaround.
But also make sure you close the instance. In fact, considering you're trying to use a background thread for your query, you should consider using realm.copyFromRealm(realmResults)
so that you can close the instance freely.
Realm save data in one thread acquire in another
I found a workaround - even if I don't need any transaction I call .beginTransaction() before call where(clazz.class) and data is up to date.
Wait for data update in realm-java between threads
A possible hack would be to create a transaction that you cancel at the end.
realm.beginTransaction(); // blocks while there are other transactions
... // you always see the latest version of the Realm here
realm.cancelTransaction();
This works if the thread is started after the UI thread saves the object into the Realm.
You can also try this workaround: https://stackoverflow.com/a/38839808/2413303 (although it doesn't really help with waiting)
Related Topics
Android: Change Shape Color in Runtime
Is There Any Limit of Bundle in Android
What Is the Purpose of Android's <Merge> Tag in Xml Layouts
Cursor Adapter and SQLite Example
Differencebetween Android Margin Start/End and Right/Left
Put and Get String Array from Shared Preferences
Android Datepicker Change to Only Month and Year
How to Use Multiple Mapactivities/Mapviews Per Android Application/Process
Problem to Load Flv Video in Webview
Android: Implementing Progressbar and "Loading..." for Endless List Like Android Market
How to Determine the Screen Width in Terms of Dp or Dip at Runtime in Android
Android Onclick in Xml VS. Onclicklistener
Error:(26, 0) Gradle Dsl Method Not Found: 'Runproguard()'
How to Check If an Intent Can Be Handled from Some Activity
Compile with Proguard Gives Simexception: "Local Variable Type Mismatch"