I wrote a lazy image downloader for my app using an ExecutorService. It gives me great control about how many downloads are running in parallel at what time and so on.
I had the same requirements: Lazy loading and LIFO for a better user experience. So I have used the ThreadPoolExecutor with a wrapped BlockingQueue (like mentioned before).
For easy backward compatibility I decided to go the easy way and for older devices I am simply using a fixed thread pool - wich means FIFO ordering. That's not perfect but for the first try okay. This looks like:
try {
sWorkQueue = new BlockingLifoQueue();
sExecutor = (ThreadPoolExecutor) Class.forName("java.util.concurrent.ThreadPoolExecutor").getConstructor(int.class, int.class, long.class, TimeUnit.class, BlockingQueue.class).newInstance(3, DEFAULT_POOL_SIZE, 10, TimeUnit.MINUTES, sWorkQueue);
if (BuildConfig.DEBUG) Log.d(LOG_TAG, "Thread pool with LIFO working queue created");
} catch (Exception e) {
if (BuildConfig.DEBUG) Log.d(LOG_TAG, "LIFO working queues are not available. Using default fixed thread pool");
sExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);
}