package com.netease.LDNetDiagnoService;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
/**
*
* @author liujie
*
* <p>
* The most part is copied for {@link AsyncTask}.
*
* What's we do here is to control the executor and the core
*
* number of thread parallely.
*
* <p>
* Since Starting with HONEYCOMB, tasks are executed on a single thread
*
* to avoid common application errors caused by parallel execution.
*/
public abstract class LDNetAsyncTaskEx<Params, Progress, Result> {
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 volatile Status mStatus = Status.PENDING;
public enum Status {
PENDING, RUNNING, FINISHED,
}
private static final LDNetInternalHandler sHandler = new LDNetInternalHandler();
private final LDNetWorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
// protected Hashtable<Params, LDNetAsyncTaskEx> mTaskCache = new
// Hashtable<Params, LDNetAsyncTaskEx>();
public LDNetAsyncTaskEx() {
mWorker = new LDNetWorkerRunnable<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(this.getClass().getSimpleName(), 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 LDNetAsyncTaskResult<Result>(LDNetAsyncTaskEx.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 LDNetAsyncTaskResult<Result>(LDNetAsyncTaskEx.this, result));
message.sendToTarget();
}
};
}
private static class LDNetInternalHandler extends Handler {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void handleMessage(Message msg) {
LDNetAsyncTaskResult result = (LDNetAsyncTaskResult) 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;
}
}
}
public final Status getStatus() {
return mStatus;
}
protected abstract Result doInBackground(Params... params);
/**
* 后台线程准备运行阶段
*/
protected void onPreExecute() {
}
/**
* 后台运行阶段,当前运行已经结束
* @param result
*/
protected void onPostExecute(Result result) {
}
/**
* 进度更新阶段
* @param values
*/
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);
}
/**
* 初始化运行阶段
* @param params
* @return
*/
@SuppressWarnings("incomplete-switch")
public final LDNetAsyncTaskEx<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;
ThreadPoolExecutor sExecutor = getThreadPoolExecutor();
// ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
// MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue,
// sThreadFactory);
if (sExecutor != null) {
sExecutor.execute(mFuture);
return this;
} else {
return null;
}
}
protected abstract ThreadPoolExecutor getThreadPoolExecutor();
protected final void publishProgress(Progress... values) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new LDNetAsyncTaskResult<Progress>(this, values)).sendToTarget();
}
protected void finish(Result result) {
if (isCancelled()) {
result = null;
}
onPostExecute(result);
mStatus = Status.FINISHED;
}
private static abstract class LDNetWorkerRunnable<Params, Result> implements
Callable<Result> {
Params[] mParams;
}
private static class LDNetAsyncTaskResult<Data> {
@SuppressWarnings("rawtypes")
final LDNetAsyncTaskEx mTask;
final Data[] mData;
LDNetAsyncTaskResult(@SuppressWarnings("rawtypes") LDNetAsyncTaskEx task,
Data... data) {
mTask = task;
mData = data;
}
}
}