I'm writing my own ContentProvider which will be synced to a web service using a SyncAdapter.
Problem happens when the sync adapter is modifying the content provider's data the provider triggers a network sync when internally calling getContentResolver().notifyChange causing a sync loop.
The notifyChange with the network sync flag is required for when a client application does the modification but should be avoided when the sync adapter is modifying.
How can one, inside a contentprovider, easly tell if it's being used by a client application (which should trigger network sync upon modification) or by a sync adapter (which should not trigger network sync).
Currently I'm using different CONTENT_URI's (sync adapter accesses the data using a CONTENT_URI_NO_SYNC and client apps using a CONTENT_URI) to be able to distinguish between the two types of access and set the network sync flag accordingly.
Watch this video about REST API usage in SyncAdapter
s.
The method they discuss is to add a set of metadata flags columns to the database. This allows us to do 3 things.
The flags themselves allow the SyncAdapter
to determine the rows that need changes and what those changes are. How do you tell the difference between a locally created row and a locally modified row? Furthermore how do you know which REST API call to make? If you just delete a row, how does your SyncAdapter
know the row to be deleted if the data is now gone? Instead, set the "Should be deleted" flag, and then, when the SyncAdapter
runs, it knows to push a delete to the server.
The flags allow your CursorAdapter
to modify the view that is created (like adding a Spinner
to show that "This row is being synced")
Finally, and this they don't point out, the flags allow you to tell why the row is being modified. If none of the flags are set and the row changes, it must have been because of an update from the server. Therefore, no need to sync to network.
So, the two workflows are as follows:
Local change
notifyChange(...,true);
SyncAdapter
to fire. SyncAdapter
scans the database, finds the row with create flag set and performs appropriate server action. After success, SyncAdapter
clears the flag.(row update on ContentProvivder
)ContentProvider
sees the flag clear, no flags are left set, so it calls notifyChange(...,false);ContentObserver
s see the flag change, update to look like "sync finished"All these steps are equivalent for update / delete -- one flag per syncable row for each of create/update/delete. Also notice the other win -- what if "Create" fails temporarily? server down... How do you know to retry? -- Simple, you don't clear the "Create" flag and you see it 15 minutes later.
Remote Change
SyncAdapter
fires due to periodic sync. SyncAdapter
fetches an update from the server. Pushes changes into the database. Doesn't set any flags. ContentProvider
sees the lack of flags, knows the change must have come from the server (or isn't a database change that needs to be pushed to the server), so it calls notifyChange(...,false);
ContentObserver
s see the content change and so they update with new row dataIf 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