package by.fksis.schedule.async.base;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AsyncTaskEx<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTaskEx";
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 9000;
private static final int KEEP_ALIVE = 10;
private static final LinkedBlockingQueue<Runnable> sWorkQueue = new LinkedBlockingQueue<Runnable>();
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTaskEx #" + mCount.getAndIncrement());
}
};
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static final int MESSAGE_POST_CANCEL = 0x3;
private static final InternalHandler sHandler = new InternalHandler();
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
private volatile Status mStatus = Status.PENDING;
public enum Status {
PENDING, RUNNING, FINISHED,
}
public static void clearQueue() {
sWorkQueue.clear();
}
public AsyncTaskEx() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return doInBackground(mParams);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@SuppressWarnings("unchecked")
@Override
protected void done() {
Message message;
Result result = null;
try {
result = get();
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()", e.getCause());
} catch (CancellationException e) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL, new AsyncTaskExResult<Result>(
AsyncTaskEx.this, (Result[]) null));
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing " + "doInBackground()", t);
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskExResult<Result>(AsyncTaskEx.this,
result));
message.sendToTarget();
}
};
}
public final Status getStatus() {
return mStatus;
}
protected abstract Result doInBackground(Params... params);
protected void onPreExecute() {
}
protected void onPostExecute(Result result) {
}
protected void onProgressUpdate(Progress... values) {
}
protected void onCancelled() {
}
public final boolean isCancelled() {
return mFuture.isCancelled();
}
public final boolean cancel(boolean mayInterruptIfRunning) {
return mFuture.cancel(mayInterruptIfRunning);
}
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get();
}
public final Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException,
TimeoutException {
return mFuture.get(timeout, unit);
}
public final AsyncTaskEx<Params, Progress, Result> executePrioritized(Params... params) {
execute(params);
Queue<Runnable> q = sExecutor.getQueue();
try {
synchronized (q) {
for (int i = 0; i < q.size() - 1; i++)
if (!q.isEmpty())
q.add(q.remove());
}
} catch (Exception e) {
e.printStackTrace();
}
return this;
}
public final AsyncTaskEx<Params, Progress, Result> execute(Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:" + " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:" + " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
sExecutor.execute(mFuture);
return this;
}
protected final void publishProgress(Progress... values) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskExResult<Progress>(this, values)).sendToTarget();
}
private void finish(Result result) {
onPostExecute(result);
mStatus = Status.FINISHED;
}
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public void handleMessage(Message msg) {
AsyncTaskExResult result = (AsyncTaskExResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
case MESSAGE_POST_CANCEL:
result.mTask.onCancelled();
break;
}
}
}
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
@SuppressWarnings("rawtypes")
private static class AsyncTaskExResult<Data> {
final AsyncTaskEx mTask;
final Data[] mData;
AsyncTaskExResult(AsyncTaskEx task, Data... data) {
mTask = task;
mData = data;
}
}
}