[Android] Flaming Durtles - Android app with offline support

Well, I don’t want to bore you with technical details that may or may not mean anything to you, but here’s the general idea: it was a subtle timing issue, also known as a race condition.

A lot of the work the app does is done in the background to make sure the app doesn’t (for example) freeze up when it talks to the API. Parts of the app send messages to each other to get all the necessary work done. For example, when you correctly answer both reading and meaning for a subject:

  1. The foreground tells the background to process the review result in the database, and schedule your next review for the subject.
  2. The background tells the foreground that the subject has changed (new SRS stage, new ‘next review’ date, …) so that the foreground can show the changes immediately.
  3. The foreground chooses the next question and tells the background to load the new subject from the database.
  4. The foreground tells the background to schedule a sync task to sync the review result to the API.
  5. And a bunch more…

The problem is/was that steps 2 and 3 can happen at exactly the same time if your device is not too fast and not too slow, but exactly a particular speed. If that happened, the foreground got confused and mixed up the work for steps 2 and 3. And in the worst-case scenario, that means the app is now presenting a question for a new subject, while it’s judging the answer against the old subject that you just finished.

So the app might quiz you on 木 which you answer correctly, and then show you 山. You type “mountain”, but the app still thinks you’re on 木 so it expects you to answer “tree”, so it says “mountain” is wrong. But the answer is still marked as “incorrect” on 山.

This only goes wrong if the timing is exactly the worst it can possibly be. And that’s why I can’t reproduce it for myself: all of my physical devices are too fast, and all of my emulated devices are too slow, so I never saw that bad timing happen.

The solution is that the foreground now waits until it is done with its own messages before it will pick up new messages from the background. I was a bit sloppy there and I basically had the background just shove a couple of its messages down the foreground’s throat, whether it was ready for it or not. Usually that works fine, but it turns out it can also go wrong…

4 Likes