views:

53

answers:

2

Our Android app does a lot of image decoding. We fetch a lot of images from the internet, local storage caches, etc.

Up to now, these images are being decoded on the UI thread (using BitmapFactory.decodeX() methods). It's been causing some timeout crashes because the UI doesn't respond quickly enough to user input.

I could write a little AsyncTask that encapsulates decoding, but I'm not sure that's a good idea. Spawning threads is expensive, and that would be spawning and tearing down a ton of them.

So what's the best way to put this on another thread? Do I need to go to the extent of writing a Service? That seems a little heavy-weight. Are there any solutions for this already out there?

+1  A: 

AsyncTask keeps a pool of threads, so you don't pay much cost for using several instances of AsyncTasks. Either use AsyncTask or use a single thread with a request queue to decode the images.

Romain Guy
@Romain Guy - Yeah I hadn't looked at the code for AsyncTask--you'd think they'd mention the thread pooling. Anyway, looks like it can still spawn up to 10 threads (yikes), which means during heavy image processing I'd be paying a large overhead for context switching, slowing down the processing of individual images. Since I want these processed roughly FIFO anyway, it sounds like an ImageService will be more efficient. I like AsyncTask, but I think it's better suited to things like network requests.
DougW
AsyncTask really was meant to perform one off operations, for instance after clicking a button. It is not a generic threading solution. Also, AsyncTask does not mention the thread pool on purpose to avoid committing to a specific implementation.
Romain Guy
@Romain Guy - All fair points. I do think it's valid to point out implementation details with huge performance implications with the caveat that they may change, but I take your point.
DougW
+1  A: 

You can use an IntentService to que up your download/decodes just call startService() for each image all at once and it will do them one at a time. then you can pass it back to your activity with a ResultReceiver

schwiz
For the record, we did not end up using this. It's still better than a plain AsyncTask for this type of thing. AsyncTask is suited to activities that block, but do not perform intensive computation. The problem is that AsyncTask spawns up to 5 threads, queues 10 tasks, then spawns up to !!128!! threads once the queue is full. If you ran 30 image decoding tasks at once, goodbye app, hello ANR crash. On the up side it does thread pooling. Ultimately, we wrote an extension of AsyncTask that has its own queue and only allows one task to run at a time.
DougW
cool glad you found a solution that worked for you!
schwiz