package org.emdev.ui.tasks; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.emdev.common.android.AndroidVersion; import org.emdev.utils.collections.ArrayDeque; public class AsyncTaskExecutor { static final AsyncTaskExecutor DEFAULT = new AsyncTaskExecutor(10, 5, 128, 1, "AsyncTask"); static final boolean USE_PARALLEL_AS_DEFAULT = AndroidVersion.lessThan3x; private final ThreadFactory threadFactory; private final BlockingQueue<Runnable> poolWorkQueue; private final Executor executor; private final SerialExecutor serial; public AsyncTaskExecutor(final int maxQueueSize, final int corePoolSize, final int maximumPoolSize, final long keepAliveTime, final String threadName) { threadFactory = new DefaultThreadFactory(threadName); poolWorkQueue = new ArrayBlockingQueue<Runnable>(maxQueueSize); executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, poolWorkQueue, threadFactory); serial = new SerialExecutor(); } @SuppressWarnings("unchecked") public <Params, Progress, Result, Task extends AsyncTask<Params, Progress, Result>> Task execute(final Task task, final Params... params) { return (Task) task.executeOnExecutor(executor, params); } @SuppressWarnings("unchecked") <Params, Progress, Result, Task extends AsyncTask<Params, Progress, Result>> Task executeAsDefault(final Task task, final Params... params) { return (Task) task.executeOnExecutor(USE_PARALLEL_AS_DEFAULT ? executor : serial, params); } private static final class DefaultThreadFactory implements ThreadFactory { private final AtomicInteger mCount = new AtomicInteger(1); private final String threadName; private DefaultThreadFactory(final String threadName) { super(); this.threadName = threadName; } @Override public Thread newThread(final Runnable r) { return new Thread(r, threadName + "-" + mCount.getAndIncrement()); } } private class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; @Override public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { @Override public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { executor.execute(mActive); } } } }