package org.wikipedia.concurrency;

import android.os.AsyncTask;

import org.wikipedia.util.log.L;

public abstract class SaneAsyncTask<T> extends AsyncTask<Void, Void, T> {
    private Throwable thrown;

    public abstract T performTask() throws Throwable;

    public void onBeforeExecute() { }

    public void onFinish(T result) { }

    public void onCatch(Throwable caught) { }

    public void execute() {
        super.executeOnExecutor(AsyncTask.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();
    }
}
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();
    }
}

Reimplement AsyncTask thread pool in SaneAsyncTask