addModelChangeListener is triggered multiple times
ISSUE_TEMPLATE
DBFlow Version: 4.2.4
Bug or Feature Request: addModelChangeListener is triggered multiple times
Description: I have 10 tables registered for content changes. When I do a normal item.save(), the addModelChangeListener is triggered 5 - 20 times.
do you mean the method addModelChangeListener?
observer = new FlowContentObserver(BuildConfig.APPLICATION_ID + ".authority");
observer.setNotifyAllUris(false);
observer.addModelChangeListener((table, action, primaryKeyValues) -> {
/// This part is executed multiple times
});
I need to get the table name where the row was modified. Sometimes by doing :
FlowManager.getTableName(table).replaceAll("`", "");
It's throwing Exception :
11-07 18:18:13.202 8803-11209/com.axxessio.axxpos W/Binder: Caught a RuntimeException from the binder stub implementation.
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Class.getName()' on a null object reference
at com.raizlabs.android.dbflow.config.FlowManager.getDatabaseForTable(FlowManager.java:141)
at com.raizlabs.android.dbflow.config.FlowManager.getModelAdapterOrNull(FlowManager.java:469)
at com.raizlabs.android.dbflow.config.FlowManager.getTableName(FlowManager.java:79)
at com.axxessio.axxpos.server.SyncController.lambda$observeSyncChangeLogTable$4(SyncController.java:131)
at com.axxessio.axxpos.server.-$$Lambda$SyncController$-XKgCVbUs8gjqBEic0pbirsM7l8.onModelStateChanged(lambda)
at com.raizlabs.android.dbflow.runtime.FlowContentObserver.onChange(FlowContentObserver.java:285)
at com.raizlabs.android.dbflow.runtime.FlowContentObserver.onChange(FlowContentObserver.java:254)
at android.database.ContentObserver.onChange(ContentObserver.java:145)
at android.database.ContentObserver.dispatchChange(ContentObserver.java:196)
at android.database.ContentObserver.access$000(ContentObserver.java:27)
at android.database.ContentObserver$Transport.onChange(ContentObserver.java:231)
at android.database.IContentObserver$Stub.onTransact(IContentObserver.java:62)
at android.os.Binder.execTransact(Binder.java:453)
Why is it even possible to get the table as null ?
in 5.0.0-alpha1 with Kotlin we have almost full null safety involved and that will not happen. As for now I'd recommend checking for null and discard any event that returns a null table. As for why that is happening - it may be receiving events from other tables since its likely using the same Context object when you register the observer. My advice would be to switch to a DirectModelObserver if you don't need the ContentResolver functionality for now and that should work the way you want. In 5.0.0+ I am planning on overhauling the notification system to work as expected and efficiently as possible.
Basically what I need to achieve is whenever we add or modify a row, I need to get the table name and rowId to push it to the server. What would you recommend for that ? Also I couldn't find DirectModelObserver in 4.2.4 . There is only DirectModelNotifier which has private acces.
UPD: Okey I've found how to use DirectModelNotifier but it requires to set Listener for every table. Or is there other way to make as with FlowContentObserver ?
DirectModelNotifier is a little different in implementation. use DirectModelNotifier.get() to utilize the instance and register / deregister for ModelChangedListener. It'll give you the direct model object and what changed. You can get it's id and class (which is the table) from the callback. And in your DB you'll need to override the default ContentResolverNotifier to switch to it.
https://dbflow.gitbook.io/dbflow/v/develop/usage2/usage/observability#direct-changes
Even though the doc is for 5.0.0+, it's very similar on how to utilize it.
Future plans would try to involve utilizing db triggers and checking for changes to a new, custom table which keeps track of these changes in the SQLite layer, thus working with any kind of DB modification or query pretty efficiently.
@agrosner I've just tried to use DirectModelNotifier but anyway it's executed twice(still better than previously). But I didn't try to put multiple listeners(for each table).
I've just put a log into the ModelChangeListener and that's the result:
11-07 20:50:13.380 12163-12163/com E/myLogs: Unit
11-07 20:50:13.381 12163-12163/com E/myLogs: Unit
11-07 20:50:22.771 12163-12163/com E/myLogs: Unit
11-07 20:50:22.771 12163-12163/com E/myLogs: Unit
That's on Inserting new Items. like
Unit u = new Unit()
u.setName();
u.setDate();
u.setFoo();
u.save();
Maybe I am doing something wrong ?
DbFlow: v 4.2.4
I have tried both addOnTableChangedListener and addModelChangeListener and they are trigged for all the Models not just the one we have registered for. ( check this )
In case of the non registered tables the Class<?> table` is null.
My temporary workaround is to add a null check for Class<?> table
observer.addModelChangeListener((table, action, parameters) -> {
if(table != null){
doSomthing(table, action,parameters);}
});