package in.srain.cube.concurrent;
import android.os.Handler;
import android.os.Message;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A class which encapsulate a task that can execute in background thread and can be cancelled.
*
* @author http://www.liaohuqiu.net
*/
public abstract class SimpleTask implements Runnable {
private static final int STATE_NEW = 0x01;
private static final int STATE_RUNNING = 0x02;
private static final int STATE_COMPLETING = 0x04;
private static final int STATE_CANCELLED = 0x08;
private static final int MSG_TASK_DONE = 0x01;
private static InternalHandler sHandler = new InternalHandler();
private Thread mCurrentThread;
private AtomicInteger mState = new AtomicInteger(STATE_NEW);
/**
* A worker will execute this method in a background thread
*/
public abstract void doInBackground();
/**
* will be called after doInBackground();
*/
public abstract void onFinish();
/**
* When the Task is Cancelled.
*/
protected void onCancel() {
}
/**
* Restart the task, just set the state to {@link #STATE_NEW}
*/
public void restart() {
mState.set(STATE_NEW);
}
@Override
public void run() {
if (!mState.compareAndSet(STATE_NEW, STATE_RUNNING)) {
return;
}
mCurrentThread = Thread.currentThread();
doInBackground();
sHandler.obtainMessage(MSG_TASK_DONE, this).sendToTarget();
}
/**
* check whether this work is canceled.
*/
public boolean isCancelled() {
return mState.get() == STATE_CANCELLED;
}
/**
* check whether this work has done
*
* @return
*/
public boolean isDone() {
return mState.get() == STATE_COMPLETING;
}
public void cancel(boolean mayInterruptIfRunning) {
if (mState.get() >= STATE_COMPLETING) {
return;
} else {
if (mState.get() == STATE_RUNNING && mayInterruptIfRunning && null != mCurrentThread) {
try {
mCurrentThread.interrupt();
} catch (Exception e) {
}
}
mState.set(STATE_CANCELLED);
onCancel();
}
}
private static class InternalHandler extends Handler {
@Override
public void handleMessage(Message msg) {
SimpleTask work = (SimpleTask) msg.obj;
switch (msg.what) {
case MSG_TASK_DONE:
work.mState.set(STATE_COMPLETING);
work.onFinish();
break;
default:
break;
}
}
}
public static void postDelay(Runnable r, long delayMillis) {
sHandler.postDelayed(r, delayMillis);
}
}