In the ContentObserver class, the method onChange is passed a boolean selfChange that's defined as: "true if the update was caused by a call to commit on the cursor that is being observed."
What's the proper way to update the cursor so that selfChange is set to true? My current code doesn't reference the cursor at all for an update and selfChange is always false as a result.
ContentValues values = new ContentValues();
values.put("date", date.getTime());
getContentResolver().update(URI, values, "_id = " + id, null);
The Android framework does not provide a way to do this through the static ContentResolver#update()
method.
Explanation
When ContentResolver#notifyChange(Uri,ContentObserver)
is called with the ContentObserver
object as the observer that initiated the change, that ContentObserver
will have onChange()
called with selfChange
set to true
From the docs:
void android.content.ContentResolver.notifyChange(Uri uri, ContentObserver observer)
Parameters:
uri The uri of the content that was changed.
observer The observer that originated the change, may be null. The observer that originated the change will only receive the notification if it has requested to receive self-change notifications by implementing ContentObserver.deliverSelfNotifications() to return true.
So if you're calling notifyChange()
from within your ContentProvider
update/insert/delete methods which are in turn being called from the ContentResolver
update/insert/delete methods, you won't have the ContentObserver
reference to pass to notifyChange()
and so won't have selfChange
set to true.
Workaround
This will work if the ContentProvider is in the same process as the client code. It requires a custom ContentProvider and a more complex/error prone calling of the update/insert/delete methods.
We can create custom methods in our derived ContentProvider
that take a ContentObserver
as a parameter. For example, if we wanted to have the update()
method call notifyChange()
with the ContentObserver
we would do something like:
public class MyContentProvider extends ContentProvider {
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// Just call our new method with 'null' as the ContentObserver
update(uri,values,selection,selectionArgs,null);
}
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs, ContentObserver changeOriginator){
// Do the update
...
// Notify the change with the ContentObserver that wants to ignore it
getContext().getContentResolver().notifyChange(uri,changeOriginator);
}
To use the new method, you'll have to get the ContentProvider
object from the ContentResolver
and call our new update()
method:
ContentProvider cP = getContentResolver().acquireContentProviderClient(URI).getLocalContentProvider();
MyContentProvider mCP = (MyContentProvider)cP;
mCP.update(URI, values, "_id = " + id, null, contentProvider);
I was experiencing the same issue. It seems you have a customized ContentProvider.
Please take a look at your implementation of your method: ContentProvider.update(Uri uri, ContentValues cv, String selection, String[] selectionArgs);
My guess is you have getContext.getContentResolver.notifyChange(Uri uri, ContentValues cv)
implemented in your customized update method, which notify ContentProvider everytime it's called, and ContentObserver receives the notification, and in turn calls the update method.
So the infinite loop forms.
Also, my life with android has a very detail yet clear explanation on how it works fully.
Hope it helps!
Happy coding!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With