RealmChangeListener does not get called when Realm gets updated in NotificationListenerService
I'm doing Realm insertions on a extended NotificationListenerService, like this:
public class NLService extends NotificationListenerService {
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
// building realmObject here
mRealm = Realm.getDefaultInstance();
RealmHelper.saveObj(myRealmObject, mRealm);
// mRealm.waitForChange(); / mRealm.refresh();
mRealm.close();
}
}
public class RealmHelper {
public static RealmModel saveObj(RealmObject realmObject, Realm realm) {
realm.beginTransaction();
RealmObject newRealmObject = realm.copyToRealm(realmObject);
realm.commitTransaction();
return newRealmObject;
}
}
Using Realm newer than v0.88.3, not a single RealmChangeListener
(rcl) gets called if anything gets inserted in NLService
.
I tried attaching rcl's directly to Realm
, RealmResults
and RealmObject
, nothing works.
The App has for example simple rcl's for RealmResults<myRealmObject>.size()
and
several RecyclerAdapters and the rcl inside RealmRecyclerViewAdapter
is never called.
Rerunning queries however works and the "missing data" shows up. Also if anything gets inserted on ui- or any other thread, rcl's get called and "missing data" shows up.
I stayed for months on Realm 0.88.3 because I can not bring it to work with any newer Realm version. With 0.88.3 mRealm.refresh();
was called in NLService, this is not available in newer versions and .waitForChange
blocks endlessly.
Manifest.xml:
<service
android:name=".service.NLService"
android:label="@string/nl_service"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService"/>
</intent-filter>
</service>
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();