1

I am loading multiple photos from Dropbox using the Core API in Android and when making requests they are serialized.

I am getting the thumbnails to show in a grid view and when the user clicks on one of them it goes to another activity it fetches the full res version from the server.

It does this fine, but the high res version only starts to be downloaded when all the others async tasks fetching the thumbnails are finished.

So what I want to know is, is this a limitation of the Dropbox Core API? Or is there a way to make the high res async task have priority over others so it is immediately downloaded and then the others can resume.

mthandr
  • 3,062
  • 2
  • 23
  • 33
  • I recommend that you use [Picasso](http://square.github.io/picasso) - it has everything related to image loading implemented with the simplest API. – corsair992 Jan 02 '15 at 23:03
  • I would love to use Picasso, or UniversalImageLoader. The thing is I prefer using the dropbox methods that use the account and the relative file paths instead of using the public links, which also are not very simple to acquire. Is there any way to use dropbox api with Picasso or UL? – mthandr Jan 02 '15 at 23:07
  • 1
    Picasso supports custom `Downloader` implementations, and `RequestHandler` was introduced as a beta feature in 2.4, where you can define your custom `Uri` handlers. Here are some blog posts I found on implementing them with the Dropbox API: http://blog.jpardogo.com/custom-picasso-downloader and http://blog.jpardogo.com/requesthandler-api-for-picasso-library – corsair992 Jan 02 '15 at 23:30
  • that's great. Will have a look. I never used Picasso, only UL, but will give it a try. – mthandr Jan 02 '15 at 23:56

1 Answers1

2

This is due to how async tasks actually work. They don't run in parallel on 3.0+ (they used to until 3.0), because too many newbie developers weren't able to program in parallel without errors, so Google decided to change it. Instead, async tasks run on a single thread in FIFO order.

You can override this however. Instead of calling asynctask.execute(), call asynctask.executeOnExecutor() and use a THREAD_POOL_EXECUTOR. This will execute it in parallel on its own thread. I believe there's a thread cap, but it will at least make several run in parallel.

If the thread cap becomes an issue, you can always drop down to using threads instead of using async tasks. You need to do some work yourself to do an onPostExecute, but it isn't that hard. And if you're creeating your own threads you can make up to the OS limit.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • I see. I actually thought that at least some of the async tasks were running in parallel. I will try using the Executor as you suggest, and if not enough I will try my own implementation. Thanks. – mthandr Jan 02 '15 at 23:05
  • Also, is there any way to change the order of execution of the async tasks, with or without the Executor? – mthandr Jan 02 '15 at 23:13
  • The `THREAD_POOL_EXECUTOR` provided by the `AsyncTask` has a work queue that is bounded at 128 tasks, but you can define your own `ThreadPoolExecutor` without any such limitation, or even change the queue of the `AsyncTask.THREAD_POOL_EXECUTOR` or set another as the default. – corsair992 Jan 02 '15 at 23:33
  • @corsair992 Nice, didn't realize it was that high. Then if it becomes an issue you're probably doing something wrong. – Gabe Sechan Jan 02 '15 at 23:33
  • @androidpotato7: `AsyncTask` doesn't allow you to specify task priority, but it is possible after some slight modification of it. See this question: http://stackoverflow.com/questions/24461534/asynctask-on-executor-and-priorityblockingqueue-implementation-issue – corsair992 Jan 02 '15 at 23:39
  • I knew about the 128 tasks but are they or not executed at the same time (a small number of them of course). Or is it strictly FIFO order like @GabeSechan said? 128 tasks right now isn't a problem, but the strict order is. – mthandr Jan 02 '15 at 23:58
  • If you just call execute, its FIFO. If you call executeOnExecutor, its with THREAD_POOL_EXECUTOR, its parallel with a 128 cap and no prioritization. If you make a custom Executor, you can increase the cap (up to the OS limit) and/or add prioritization, but you'll have to write it yourself (it isn't built in). – Gabe Sechan Jan 03 '15 at 00:01
  • @GabeSechan: Actually, it's slightly different. The `SERIAL_EXECUTOR` is just a wrapper that delegates to the `THREAD_POOL_EXECUTOR` in a serial manner. The max thread pool size in the `THREAD_POOL_EXECUTOR` is twice the amount of available processor cores on the device plus one. The work queue used by both is a bounded `LinkedBlockingQueue`, which means that in both executors the tasks will be processed by the thread pool in FIFO order and the queued tasks will be capped at 128. This used to be implemented differently pre-Honeycomb as you described - the cap being on the thread pool itself. – corsair992 Jan 03 '15 at 00:16
  • I just changed execute() to executeOnExecutor and everything is so freaking fast! So awesome, thank you! Will need to manage the 128 tasks limit, but this is just a huge difference. – mthandr Jan 03 '15 at 00:21