JAVA版调度器
JAVA版调度器
```java
package cn.itsub.tank.timer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
/**
调度器:可以在预定的时间执行回调
回调有两种:
-- 更新回调:每一帧都会执行回调
-- 自定义回调:指定间隔时间执行回调,
推荐使用更新回调
* @site http://itsub.cn
* @author Erik.Xia
*/
public class Scheduler {
// 用于记录"目标-回调-优先级"的双链表
private static class tListEntry {
public Method impMethod;
public UpdateCallback callback;
public Object target;
public int priority;
public boolean paused;
};
// 用于记录"目标-计时-状态"
private static class tHashSelectorEntry {
ArrayList<MyTimer> timers;
Object target;
ArrayList<tListEntry> list;
tListEntry entry;
int timerIndex;
MyTimer currentTimer;
boolean currentTimerSalvaged;
boolean paused;
void setPaused(boolean b){
paused = b;
if (entry != null){
entry.paused = b;
}
}
}
//按优先级区分
ArrayList<tListEntry> updatesNeg; // list priority < 0
ArrayList<tListEntry> updates0; // list priority == 0
ArrayList<tListEntry> updatesPos; // list priority > 0
ArrayList[] updatesArray = null;
//按回调类型区分
ConcurrentHashMap<Object, tHashSelectorEntry> hashForSelectors;
ConcurrentHashMap<Object, tHashSelectorEntry> hashForUpdates;
tListEntry currentEntry;
tHashSelectorEntry currentTarget;
boolean currentTargetSalvaged;
String updateSelector;
/**
* 时间流速,默认值1.0
* 当值小于1时为慢动作,当值快于1时为快动作
* @warning 它会影响所有的调度任务.
*/
private float timeScale_;
public float getTimeScale() {
return timeScale_;
}
public void setTimeScale(float ts) {
timeScale_ = ts;
}
private static Scheduler _sharedScheduler = null;
/** 返回单例的调度器 */
public static Scheduler getInstance() {
if (_sharedScheduler != null) {
return _sharedScheduler;
}
synchronized (Scheduler.class) {
if (_sharedScheduler == null) {
_sharedScheduler = new Scheduler();
}
return _sharedScheduler;
}
}
/**
* 清除单例的调度器
*/
public static void purgeSharedScheduler() {
_sharedScheduler = null;
}
private Scheduler() {
timeScale_ = 1.0f;
// 触发时基于反射调用的方法名
updateSelector = "update";
// updates with priority
updates0 = new ArrayList<tListEntry>();
updatesNeg = new ArrayList<tListEntry>();
updatesPos = new ArrayList<tListEntry>();
updatesArray = new ArrayList[]{updatesNeg, updates0, updatesPos};
hashForUpdates = new ConcurrentHashMap<Object, tHashSelectorEntry>();
hashForSelectors = new ConcurrentHashMap<Object, tHashSelectorEntry>();
// selectors with interval
currentTarget = null;
currentTargetSalvaged = false;
}
/**
* 滴答(你不应该调用这个方法,除非你知道你在做什么)
*/
public void tick(float dt) {
if( timeScale_ != 1.0f )
dt *= timeScale_;
currentTargetSalvaged = false;
for (int n = 0; n < updatesArray.length; n++) {
ArrayList<tListEntry> list = updatesArray[n];
synchronized (list) {
try {
for (int i = 0; i < list.size(); i++) {
tListEntry e = list.get(i);
currentEntry = e;
if( ! e.paused ) {
if(e.callback !=null) {
e.callback.update(dt);
} else {
try {
e.impMethod.invoke(e.target, dt);
} catch (InvocationTargetException e1) {
if(e1.getTargetException() instanceof RuntimeException)
throw (RuntimeException)e1.getTargetException();
else
e1.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if(currentTargetSalvaged) {
list.remove(e);
i--;
currentTargetSalvaged = false;
}
}
}
} catch(IndexOutOfBoundsException e) {
e.printStackTrace();
}
currentEntry = null;
}
}
Iterator<Entry<Object, tHashSelectorEntry>> it = hashForSelectors.entrySet().iterator();
while(it.hasNext()){
Entry<Object, tHashSelectorEntry> e = it.next();
tHashSelectorEntry elt = e.getValue();
currentTarget = elt;
currentTargetSalvaged = false;
if( ! currentTarget.paused && elt.timers != null) {
// Timers数组可能在循环中更改。
for( elt.timerIndex = 0; elt.timerIndex < elt.timers.size(); elt.timerIndex++) {
elt.currentTimer = elt.timers.get(elt.timerIndex);
elt.currentTimerSalvaged = false;
elt.currentTimer.update(dt);
if( elt.currentTimerSalvaged ) {
elt.currentTimer = null;
}
}
}
// 如果没有行动计划则删除currentTarget
if( currentTargetSalvaged && currentTarget.timers.isEmpty()) {
hashForSelectors.remove(elt.target);
}
}
currentTarget = null;
}
static class SchedulerTimerAlreadyScheduled extends RuntimeException {
private static final long serialVersionUID = -3460936783625533341L;
public SchedulerTimerAlreadyScheduled(String reason) {
super(reason);
}
}
static class SchedulerTimerNotFound extends RuntimeException {
private static final long serialVersionUID = -1912889437889458701L;
public SchedulerTimerNotFound(String reason) {
super(reason);
}
}
/**
* 每隔一段时间都会执行一次target对象的方法,selector用于指定方法名称,interval是间隔秒数,
* 如果interval为0,则每一帧都会执行,如果这样,我们推荐使用'scheduleUpdateForTarget'
*/
public void schedule(String selector, Object target, float interval, boolean paused) {
assert selector != null: "Argument selector must be non-nil";
assert target != null: "Argument target must be non-nil";
tHashSelectorEntry element = hashForSelectors.get(target);
if( element == null ) {
element = new tHashSelectorEntry();
element.target = target;
hashForSelectors.put(target, element);
element.paused = paused;
} else {
assert element.paused == paused : "Scheduler. Trying to schedule a selector with a pause value different than the target";
}
if( element.timers == null) {
element.timers = new ArrayList<MyTimer>();
}
MyTimer timer = new MyTimer(target, selector, interval);
element.timers.add(timer);
}
/**
* 向target对象添加计时任务,每隔一段时间都会执行一次callback,
* interval是间隔秒数,如果interval为0,则每一帧都会执行
*/
public void schedule(UpdateCallback callback, Object target, float interval, boolean paused) {
assert callback != null: "Argument callback must be non-nil";
assert target != null: "Argument target must be non-nil";
tHashSelectorEntry element = hashForSelectors.get(target);
if( element == null ) {
element = new tHashSelectorEntry();
element.target = target;
hashForSelectors.put(target, element);
element.paused = paused;
} else {
assert element.paused == paused : "HiScheduler. Trying to schedule a selector with a pause value different than the target";
}
if( element.timers == null) {
element.timers = new ArrayList<MyTimer>();
}
MyTimer timer = new MyTimer( callback, interval);
element.timers.add(timer);
}
/**
* 从目标上移除指定方法名的任务
*/
public void unschedule(String selector, Object target) {
if( target==null &##124;&##124; selector==null)
return;
assert target != null: "Target MUST not be null";
assert selector != null: "Selector MUST not be null";
tHashSelectorEntry element = hashForSelectors.get(target);
if( element != null ) {
for( int i=0; i< element.timers.size(); i++ ) {
MyTimer timer = element.timers.get(i);
if(selector.equals(timer.getSelector())) {
if( timer == element.currentTimer && !element.currentTimerSalvaged ) {
element.currentTimerSalvaged = true;
}
element.timers.remove(i);
if( element.timerIndex >= i )
element.timerIndex--;
if( element.timers.isEmpty()) {
if( currentTarget == element ) {
currentTargetSalvaged = true;
} else {
hashForSelectors.remove(element.target);
}
}
return;
}
}
}
}
/*
* 从目标上移除callback任务
*/
public void unschedule(UpdateCallback callback, Object target) {
// 显式地处理零参数去除对象时
if( target==null &##124;&##124; callback==null)
return;
assert target != null: "Target MUST not be null";
assert callback != null: "Selector MUST not be null";
tHashSelectorEntry element = hashForSelectors.get(target);
if( element != null ) {
for( int i=0; i< element.timers.size(); i++ ) {
MyTimer timer = element.timers.get(i);
if(callback == timer.getCallback()) {
if( timer == element.currentTimer && !element.currentTimerSalvaged ) {
element.currentTimerSalvaged = true;
}
element.timers.remove(i);
if( element.timerIndex >= i )
element.timerIndex--;
if( element.timers.isEmpty()) {
if( currentTarget == element ) {
currentTargetSalvaged = true;
} else {
hashForSelectors.remove(element.target);
}
}
return;
}
}
}
}
/**
* 注销目标身上的Update任务
*/
public void unscheduleUpdate(Object target) {
if( target == null )
return;
tHashSelectorEntry entry = hashForUpdates.get(target);
if ( entry == null )
return;
synchronized (entry.list) {
if(currentEntry==entry.entry) {
currentTargetSalvaged = true;
} else {
entry.list.remove(entry.entry);
}
}
hashForUpdates.remove(target);
}
/**
* 注销目标所有的任务
*/
public void unscheduleAllSelectors(Object target) {
if( target == null )return;
// 注销'自定义选择器'
tHashSelectorEntry element = hashForSelectors.get(target);
if( element != null) {
if(!element.currentTimerSalvaged ) {
element.currentTimerSalvaged = true; //标记为可移除
}
element.timers.clear();
if( currentTarget == element )
currentTargetSalvaged = true; //标记为可移除
else {
hashForSelectors.remove(element.target);
}
}
// 注销'Update选择器'
this.unscheduleUpdate(target);
}
/**
* 取消所有调度任务(不要调用这个方法,除非你知道自己在做什么)
*/
public void unscheduleAllSelectors() {
// 遍历'自定义选择器'
Iterator<Entry<Object, tHashSelectorEntry>> it = hashForSelectors.entrySet().iterator();
while(it.hasNext()){
Entry<Object, tHashSelectorEntry> e = it.next();
tHashSelectorEntry element = e.getValue();
Object target = element.target;
unscheduleAllSelectors(target);
}
// 遍历'Update选择器'
for (tListEntry entry:updates0) {
unscheduleUpdate(entry.target);
}
for (tListEntry entry:updatesNeg) {
unscheduleUpdate(entry.target);
}
for (tListEntry entry:updatesPos) {
unscheduleUpdate(entry.target);
}
}
/**
* 恢复目标的调度任务,如果参数为空则什么也不发生
*/
public void resume(Object target) {
assert target != null: "target must be non nil";
// Custom Selectors
tHashSelectorEntry element = hashForSelectors.get(target);
if( element != null )
element.paused = false;
// Update selector
tHashSelectorEntry elementUpdate = hashForUpdates.get(target);
if( elementUpdate != null) {
assert elementUpdate.target != null: "resumeTarget: unknown error";
elementUpdate.setPaused(false);
}
}
/**
* 暂停目标的调度任务,如果参数为空则什么也不发生
*/
public void pause(Object target) {
assert target != null: "target must be non nil";
// Custom selectors
tHashSelectorEntry element = hashForSelectors.get(target);
if( element != null )
element.paused = true;
// Update selectors
tHashSelectorEntry elementUpdate = hashForUpdates.get(target);
if( elementUpdate != null) {
assert elementUpdate.target != null:"pauseTarget: unknown error";
elementUpdate.setPaused(true);
}
}
/**
* 给目标注册一个指定优先级的任务。每一帧都会调用目标的update方法。优先级越低,它被调用的越早。
* @param target 目标
* @param priority 优先级
* @param paused 是否暂停
*/
public void scheduleUpdate(Object target, int priority, boolean paused) {
// if (Config.DEBUG) {
// tHashSelectorEntry hashElement = hashForUpdates.get(target);
// assert hashElement == null:"Scheduler: You can't re-schedule an 'update' selector'. Unschedule it first";
// }
// 大部分的更新都是0
if( priority == 0 ) {
this.append(updates0, target, paused);
} else if( priority < 0 ) {
this.priority(updatesNeg, target, priority, paused);
} else { // priority > 0
this.priority(updatesPos, target, priority, paused);
}
}
/**
* 给目标注册一个指定优先级的任务。每一帧都会调用目标的update方法。优先级越低,它被调用的越早。
* @param target 目标
* @param priority 优先级
* @param paused 是否暂停
*/
public void scheduleUpdate(UpdateCallback target, int priority, boolean paused) {
// if (Config.DEBUG) {
// tHashSelectorEntry hashElement = hashForUpdates.get(target);
// assert hashElement == null:"HiScheduler: You can't re-schedule an 'update' selector'. Unschedule it first";
// }
if( priority == 0 ) {
this.append(updates0, target, paused);
} else if( priority < 0 ) {
this.priority(updatesNeg, target, priority, paused);
} else { // priority > 0
this.priority(updatesPos, target, priority, paused);
}
}
@Override
public void finalize () throws Throwable {
unscheduleAllSelectors();
_sharedScheduler = null;
super.finalize();
}
public void append(ArrayList<tListEntry> list, Object target, boolean paused) {
tListEntry listElement = new tListEntry();
listElement.target = target;
listElement.paused = paused;
if(target instanceof UpdateCallback) {
listElement.callback = (UpdateCallback)target;
} else {
try {
listElement.impMethod = target.getClass().getMethod(updateSelector, Float.TYPE);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
synchronized (list) {
list.add(listElement);
}
tHashSelectorEntry hashElement = new tHashSelectorEntry();
hashElement.target = target;
hashElement.list = list;
hashElement.entry = listElement;
hashForUpdates.put(target, hashElement);
}
public void priority(ArrayList<tListEntry> list, Object target, int priority, boolean paused) {
tListEntry listElement = new tListEntry();
listElement.target = target;
listElement.priority = priority;
listElement.paused = paused;
if(target instanceof UpdateCallback) {
listElement.callback = (UpdateCallback)target;
} else {
try {
listElement.impMethod = target.getClass().getMethod(updateSelector, Float.TYPE);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
synchronized (list) {
if(list.isEmpty()) {
list.add(listElement);
} else {
boolean added = false;
int len = list.size();
for( int i = 0; i < len; i++ ) {
tListEntry elem = list.get(i);
if( priority < elem.priority ) {
list.add(i, listElement);
added = true;
break;
}
}
// Not added? priority has the higher value. Append it.
if( !added )
list.add(listElement);
}
}
tHashSelectorEntry hashElement = new tHashSelectorEntry();
hashElement.target = target;
hashElement.list = list;
hashElement.entry = listElement;
hashForUpdates.put(target, hashElement);
}
}
```