In the delete method of my ContentProvider, I have this notification instruction:
getContext().getContentResolver().notifyChange(url, null);
CursorAdapters does not refresh the view when the user deletes something.
What's wrong?
It works for insert and update operations.
Maybe a bit late but for anyone else, you should call
cursor.setNotificationUri()
in the query() method of your content provider before returning the cursor to the caller.
For example in the android contacts content provider:
ContactsProvider2.java
This is because the CursorAdapter.java class registers a content observer on the cursor to requery on change.
Edit: reading your question again, that may not have been the problem.
Related
I'm looking for a way to suspend notifications on a given ContentProvider's Uri. The use case is:
An Activity is bound to a CursorAdapter through a CursorLoader.
A Service may do a lot of batch, single-row updates on a ContentProvider.
The CursorLoader will reload its content on every row update, as the ContentProvider notifies listeners by ContentResolver#notifyChange.
Since I cannot edit the ContentProvider, and I have no control over the batch queries execution, is there a way to suspend notifications on a Uri (in the executing Service) until all of the ContentProvider-managed queries have been executed? I need this in order to avoid the flickering caused by the continuous requerying of the CursorLoader.
You cannot disable this mechanism in your Service. But you should try to batch them by using ContentProviderOperations.
I've written an introductory post about ContentProviderOperations and two additional posts covering the methods withYieldAllowed() and withBackReference() respectively.
Especially the latter one should be of interest for what you've described here.
With ContentProviderOperations you can batch multiple updates and inserts. If you then call applyBatch() on your ContentResolver object the ContentProvider executes them all at once.
Now I've never used Nicolas Klein's generator but since he is a very, very proficient Android developer and works at Google, I bet that the generated code makes use of transactions and calls notifyChange() only once for the complete batch at the end.
Exactly what you need.
Can you substitute your own ContentResolver?
You may try extends ContentResolver with your own class then and you will may override method notifyChange and realize your logic there.
In your Content provider class, inside query() method before returning the cursor, just comment the code which looks something like this
cursor.setNotificationUri(getContext().getContentResolver(), uri);
I use standard android ContentProvider and CursorLoader from support library.
I am looking for best approach for obtain information about what has changed in database.
I know that I can read and compare cursor in function:
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
}
but reading all records is probably not good solution.
Do you know good solution for this problem?
If you use a content provider, you abstract away all the changes made to the underlying database by implementing CRUD methods to insert, update, delete or retrieve an item in the database.
Sending a broadcast from the methods which you are interested would be an option to get notified of the changes being made to the database.
I recall that I had used this method to count the number of items added to the database during a refresh cycle.
Optionally you can send the Uri of the changed item as an intent extra to get a reference to the row in the database that has been changed.
Additionally you can declare a global variable to enable or disable these broadcasts to fire only during situations of interest to us.
while reading the documentation on Cursor here I read that cursor provides read/write access. I had gone through the API methods of Cursor but there is no setter method available to write into the Cursor. It would be of great help if you could provide me with code snippet. Thanks in advance
I think that's a bug in the documentation. You are quite right that there are no Cursor methods to modify the underlying data.
If you do try to modify the underlying data (by executing SQL statements, for example) while iterating over the data using a Cursor, bad things happen. If you need to make changes, you should keep a separate record of what you need to change whilst iterating with the Cursor, and then apply those changes separately once the Cursor is safely closed.
Given two URIs:
URI that is used in a ContentProvider's query method to retrieve multiple things:
content://my-authority/things
URI used in a ContentProvider's update method which points to a single thing (same URI retrieves thing 123 if used with the query method):
content://my-authority/thing/123
My Question:
In the update method is it correct to notifyChange twice, once for each URI above?
What led me to ask:
If a ListView of things is automatically kept in sync with SQLite data (via. SimpleCursorAdapter, LoaderManger.LoaderCallbacks and the first URI) if thing 123 is updated and only notifies for that id then the ListView does not get notified/reflect the update.
I'm sure I've misunderstood something and that there's a more elegant solution..
You only need to notifyChange for the second URI (if updating). If inserting you notifyChange the first URI.
I have a ListView populated via a CursorAdapter. I give my user the ability to alter the data in the list. For example, the user can mark a row as being unread (the data are messages).
Suppose my user marked a row unread. Would a proper implementation mark the row in the database as read and then requery the Cursor?
Would a proper implementation mark the row in the database as read and then requery the Cursor?
Yes, that's the right answer. The requery() will trigger an automatic update of your CursorAdapter, which will trigger an automatic update of the ListView, which will trigger an automatic smile from the user. :-)
UPDATE
The requery() method is deprecated. A better approach nowadays is to run a query to get a fresh Cursor, then use changeCursor() or swapCursor() on your CursorAdapter.
If the cursor is back by a ContentProvider and the ContentProvider issues correct notifications, the CursorAdapter will automatically refresh itself i.e. without the need to issue an explicit requery().