0

I'm using an app that uses async tasks to do short term background calculation jobs. These seem to end OK (go through onPostExecute() etc), but in the Eclipse debugger, one or more still hangs around.

Then I found this link - AsyncTask threads never die - so OK, it's about a thread pool and in theory not an issue.

Problems is however, I am also trying to use Google in-app billing code V3, and that appears to throw an exception whenever you carry out a purchase and there's already an AsyncTask thread hanging around. Catching the exception won't help - it still won't do anything.

How can I get around this? What do I need to do to guarantee the old calculation thread(s) have gone?

Community
  • 1
  • 1
nmw01223
  • 1,611
  • 3
  • 23
  • 40
  • "that appears to throw an exception whenever you carry out a purchase and there's already an AsyncTask thread hanging around" -- I would focus instead on asking a question where you provide your evidence for this and ask for help for why this is occurring. IOW, you are asking how to get rid of your pink elephant infestation, without any evidence that pink elephants exist. Since the `AsyncTask` thread pool behavior has been around for four years, by your argument, in-app billing would work on roughly zero apps, which seems unlikely. – CommonsWare Sep 30 '13 at 13:08

1 Answers1

1

Found out what is going on here, and it wasn't what I thought. I'll detail it here as it may be useful to somebody. Has nothing to do with other AsyncTask threads and thread pooling.

In the IabHelper class are two functions flagStartAsync() and flagEndAsync(). The aim of these is to produce a single pass gate (bit like wait() and signal() in traditional multi-threading) so only one async operation (that is, communications with Google Play and the server) can occur at a time. If flagStartAsync() get called while something is already going on, it produces an exception. Not terribly graceful, but effective I guess.

The flagStartAsync() 'test and set' gets called at the start of launchPurchaseFlow() among other places, and flagEndAsync gets called in handleActivityResult() - again - among other places. So providing the purchase flow does something that always produces a result, no problem. The problem is - it doesn't always.

If you look at launchPurchaseFlow() there are several paths out that will not kick off the async operation, and if one of those get taken, mAsyncInProgress (the relevant flag) gets left set.

What blew it in my case was that I hadn't checked that the item was already purchased, and 'already purchased' is one of the paths out. Mea culpa, but the problem is that I cannot convince myself that there aren't several other paths that you just cannot avoid at times. What if operation is slow and the 'purchase' button gets pressed twice, for instance? I bet there are others as well. One could catch the exception, and that would stop a crash, but it wouldn't really help if nothing came along to clear the flag in the end. I guess the exception handler could call flagEndAsync() but it has an uncomfortable 'sledgehammer to crack a nut' feel.

It strikes me that this is probably a non-robust piece of code. What I've done for now is call flagEndAsync() in the various ways out of launchPurchaseFlow(), but that is just a temporary fix. I don't know enough about the IabHelper code, but I think it needs more careful thought and I need to analyse it to see everything it does.

nmw01223
  • 1,611
  • 3
  • 23
  • 40