package in.srain.cube.concurrent;
import android.os.Handler;
import android.os.Looper;
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.
* memory require:
* <p/>
* Shadow heap size of AtomicInteger: 12 + 4 = 16 bytes;
* Shadow heap size of SimpleTask: 12 + 4 + 4 = 20. After aligned: 24 bytes;
* Retained heap size of SimpleTask: 16 + 24 = 40 bytes.
*
* @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_FINISH = 0x04;
private static final int STATE_CANCELLED = 0x08;
private static final int MSG_TASK_DONE = 0x01;
private static InternalHandler sHandler = null;
static {
sHandler = new InternalHandler(Looper.getMainLooper());
}
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(boolean canceled);
/**
* 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
*/
@SuppressWarnings({"unused"})
public boolean isDone() {
return mState.get() == STATE_FINISH;
}
public void cancel() {
if (mState.get() >= STATE_FINISH) {
return;
} else {
if (mState.get() == STATE_RUNNING && null != mCurrentThread) {
try {
mCurrentThread.interrupt();
} catch (Exception e) {
e.printStackTrace();
}
}
mState.set(STATE_CANCELLED);
onCancel();
}
}
private static class InternalHandler extends Handler {
InternalHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
SimpleTask work = (SimpleTask) msg.obj;
switch (msg.what) {
case MSG_TASK_DONE:
boolean isCanceled = work.isCancelled();
work.mState.set(STATE_FINISH);
work.onFinish(isCanceled);
break;
default:
break;
}
}
}
public static void post(Runnable r) {
sHandler.post(r);
}
public static void postDelay(Runnable r, long delayMillis) {
sHandler.postDelayed(r, delayMillis);
}
}