package org.wikipedia.concurrency; import android.os.AsyncTask; import android.support.annotation.NonNull; import org.wikipedia.util.log.L; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public abstract class SaneAsyncTask<T> extends AsyncTask<Void, Void, T> { private Throwable thrown; // Reimplement the stock AOSP AsyncTask implementation which may differ on OEM devices. private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); private static final int CORE_POOL_SIZE = CPU_COUNT + 1; private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; private static final int QUEUE_SIZE = 128; private static final int KEEP_ALIVE = 1; private static final ThreadFactory THREAD_FACTORY = new ThreadFactory() { private final AtomicInteger count = new AtomicInteger(1); @Override public Thread newThread(@NonNull Runnable runnable) { return new Thread(runnable, "AsyncTask #" + count.getAndIncrement()); } }; private static final BlockingQueue<Runnable> POOL_WORK_QUEUE = new LinkedBlockingQueue<>(QUEUE_SIZE); private static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, POOL_WORK_QUEUE, THREAD_FACTORY); public abstract T performTask() throws Throwable; public void onBeforeExecute() { } public void onFinish(T result) { } public void onCatch(Throwable caught) { } public void execute() { super.executeOnExecutor(THREAD_POOL_EXECUTOR); } public void cancel() { cancel(true); } @Override protected final T doInBackground(Void... voids) { try { return performTask(); } catch (Throwable t) { thrown = t; return null; } } @Override protected final void onPostExecute(T result) { super.onPostExecute(result); if (isCancelled()) { return; } if (thrown != null) { L.i(thrown); onCatch(thrown); } else { try { onFinish(result); } catch (Exception e) { L.i(e); onCatch(e); } } } @Override protected final void onPreExecute() { super.onPreExecute(); onBeforeExecute(); } }