In Android sticky broadcast perils I hinted that the ContentResolver.isSyncActive might not yield the results you'd expect. I described this issue in the talk I gave during the KrakDroid 2012 conference, but the chances are you weren't there, so I decided to write a blog post about it.
ContentResolver contains bunch of static methods with "sync" in their name: there is requestSync to start sync process, isSyncPending and isSyncActive for polling the sync state, addStatusChangeListener for listening for sync status and finally cancelSync for stopping the ongoing synchronization process. The list looks fine, in a sense that theoretically it's enough to implement the most sync-related functionality on the UI side. Let's see what is the relation between sync status reported by ContentResolver's sync methods and onPerformSync method in your SyncAdapter.
After calling requestSync, the sync for a given account and authority is added to the pending list, meaning that the sync will be executed as soon as possible (for example when syncs for other authorities are finished). In this state the isSyncPending returns true, the SyncStatusObservers registered with SYNC_OBSERVER_TYPE_PENDING mask will be triggered, and so on. This happens before your onPerformSync code is executed. Nothing especially surprising yet. The key point here is, you should take into consideration that your sync request might spend a lot of time in this state, especially if many other SyncAdapters are registered in the system. For example, it's a good idea to indicate this state somehow in the UI, otherwise your app might seem unresponsive.
When there are no other pending or active sync requests, your sync operation will move to active state. The onPerformSync will start executing in the background thread, SyncStatusObservers will trigger for both SYNC_OBSERVER_TYPE_ACTIVE (because the sync request enters this state) and SYNC_OBSERVER_TYPE_PENDING (because the sync request leaves this state) masks, isSyncPending will return false, and isSyncActive will return true. In the happy case, when the onPerformSync method will finish normally, the SyncStatusObservers for SYNC_OBSERVER_TYPE_ACTIVE state will trigger again, and isSyncActive will return false again. Booring.
The things get funny when the cancelSync is called during onPerformSync execution. The sync thread will be interrupted and the onSyncCancelled method in SyncAdapter will be called. The SyncStatusObservers will trigger, isSyncActive will return false and so on, and... at some point the onPerformSync method will finish execution.
Say what? Wasn't the sync thread interrupted? It was, but not in a "Bang, you're dead" way, but in a "polite" way as described by Herb Sutter. All the stuff described in the Thread.interrupt happened, but in 99% of cases it means that the thread continues to execute as usual, except the interrupted flag is now set. To really support cancelling the sync thread you'd have to define an interruption points at which you'll check this flag and return early from onPerformSync.
Things get even funnier here: when I used the isInterrupted method for polling the state of the sync thread, I got the bad case of heisenbug. In 9 cases out of 10 everything worked as expected, but every now and then the thread continued to execute even though earlier the onSyncCancelled was called. I guess somewhere else the InterruptedException was caught and never rethrown or someone else was polling the sync thread with interrupted and cleared the flag. To pinpoint the root cause of this behavior I'd have to read through a lot of code, so instead I implemented my own flag and set it in onSyncCancelled callback. Works like a charm.
Why is this an issue though? Can't we just let onPerformSync to finish in some undefined future? In most cases that's exactly the right way to think about this issue, but if the onPerformSync holds a lock on some resource like database handle, you might need to ensure that this lock is released as soon as possible after user cancels the sync.
Recap: show the sync pending state in the UI and if you really have to know when the sync has ended, do not trust the ContentResolver sync methods.
Showing posts with label sync. Show all posts
Showing posts with label sync. Show all posts
Wednesday, January 30, 2013
Tuesday, December 18, 2012
KrakDroid aftermath
I finally got some sleep after a really busy weekend. For the first time I had an opportunity to give a talk at the programming related conference. I was also responsible for a programming contest organized by the company I work at, I tried to push the new release of our product and, on top of that, I had to do some Christmas related stuff, so I didn't get much sleep.
Let's get back to the programming. I gave the talk about standard synchronization pattern on Android (SyncAdapter + Authenticator + ContentProvider) during this year's edition of KrakDroid conference. Here are the slides:
The link to recorded video can be found in the slideshare content description. I won't bother posting it here, because a) I gave the talk in Polish, and I try to keep the content of this blog in English b) I was really tired, at one point of the talk I had to stop and ask myself "What the hell am I trying to say".
Although my talk was average and there are many things I might have done better, I'm very happy I had an opportunity to give this talk. Public speaking is definitely outside of my comfort zone and I learned a lot. Here's the "conference speaker checklist" for my future self:
Let's get back to the programming. I gave the talk about standard synchronization pattern on Android (SyncAdapter + Authenticator + ContentProvider) during this year's edition of KrakDroid conference. Here are the slides:
Sync on Android from chalup
The link to recorded video can be found in the slideshare content description. I won't bother posting it here, because a) I gave the talk in Polish, and I try to keep the content of this blog in English b) I was really tired, at one point of the talk I had to stop and ask myself "What the hell am I trying to say".
Although my talk was average and there are many things I might have done better, I'm very happy I had an opportunity to give this talk. Public speaking is definitely outside of my comfort zone and I learned a lot. Here's the "conference speaker checklist" for my future self:
- Get some sleep
- Do the test run of the talk in front of the mirror
I finished the slides for my presentation half an hour before giving it, so I didn't have a chance to rehearse it. There were few points during my talk when adding a slide with a summary would make things much clearer. Which brings me to the next point: - Recap
I'm not sure how much the listeners who didn't knew anything about sync will remember from my talk. The recaps could help them remember at least some keywords they would be able to google later. - Do the test run of the talk in front of other people
But not any other people - you want your audience to be critical and at least a bit familiar with the topic. You want someone who will tell you that this part of the talk is boring or that part is not clear. - Get more sleep
Subscribe to:
Posts (Atom)