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开发者_C百科 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 yourSyncAdapter
know the row to be deleted if the data is now gone? Instead, set the "Should be deleted" flag, and then, when theSyncAdapter
runs, it knows to push a delete to the server.The flags allow your
CursorAdapter
to modify the view that is created (like adding aSpinner
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
- App creates new row. Row "create" flag is true.
- ContentProvider stores the row, sees create flag and so it calls
notifyChange(...,true);
- Sync to network = true (the final parameter) causes
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 onContentProvivder
)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 callsnotifyChange(...,false);
ContentObserver
s see the content change and so they update with new row data
精彩评论