使用ScheduledThreadPoolExecutor重复安排AndEngine的任务

时间:2013-03-07 15:33:43

标签: java android andengine

这是我第一次真正涉足Android编程,但我觉得我有更多的Java问题 - 对ScheduledThreadPoolExecutor如何工作有某种主要的误解(尽管我愿意接受它是AndEngine的想法) AnimatedSprites的问题也是如此)。基本上,我希望精灵一动不动,直到发生onFling。精灵动画,一秒后,再次停止。用户必须保持Fling-ing以通过水“游泳”精灵。我遇到的问题是动画。如果在1秒的时间内有多个Fling,则动画在停止之前只显示一帧或两帧,感觉就像“停止动画”任务正在堆叠。在我完成所有这些工作之后,我会检查并确保Flings足够长并且方向正确。当我第一次实例化ScheduledThreadPoolExecutor时,我提供的池大小为1,据我所知,这意味着它一次不能在队列中放置多个任务。最重要的是,在我调用.schedule()之前,我。删除()任务,只是为了确保那里没有任何内容。我确信这很简单,只是我对如何正确使用它有一些误解。我将在此处粘贴代码的相关部分:

...

private ScheduledThreadPoolExecutor shed = new ScheduledThreadPoolExecutor(1);
private Runnable slowDown = new Runnable(){
    public void run(){
        if (eelSprite.isAnimationRunning())
            eelSprite.stopAnimation(0);
    };
};

...

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
        float velocityY) {

    shed.remove(slowDown);
    shed.schedule(slowDown, 1000, TimeUnit.MILLISECONDS);

    if (!(eelSprite.isAnimationRunning()))
        eelSprite.animate(frame_duration, 0, 12, true);

return false;
}

1 个答案:

答案 0 :(得分:0)

这个问题涉及一个棘手的问题。 作为第一个评论,我想强调的是,在处理ExecutorService时,您应该坚持编码接口而不是实现。这应该避免你想要做的事情的一些复杂性。

例如,您提到使用remove()方法,该方法是公共的但在(Scheduled)ExecutorService接口中不存在。这意味着使用它可能需要一些您可能无法完全控制的特定于实现的行为。

来自ThreadPoolExecutor上的删除方法的Javadoc:

/**
 * Removes this task from the executor's internal queue if it is
 * present, thus causing it not to be run if it has not already
 * started.
 *
 * <p> This method may be useful as one part of a cancellation
 * scheme.  It may fail to remove tasks that have been converted
 * into other forms before being placed on the internal queue. For
 * example, a task entered using {@code submit} might be
 * converted into a form that maintains {@code Future} status.
 * However, in such cases, method {@link #purge} may be used to
 * remove those Futures that have been cancelled.
 *
 * @param task the task to remove
 * @return true if the task was removed
 */

请注意有关实现的部分可能会将您传递的Runnable转换为另一个表单,这使得remove()方法无法在您传递相同的Runnable实例时使用提交工作。 此外,请注意,无法保证您的移除工作正常,这取决于是否已经开始执行任务,在这种情况下,您必须检查竞争条件。 所以我建议你不要使用这种特殊的方法。

关于ScheduledThreadPoolExecutor的实例化,您可能也误读了javadoc。首先,我还会尽可能地使用Executors类提供的工厂方法来创建池。 Executors.newScheduledThreadPool(int)状态的javadoc:

/**
 * Creates a thread pool that can schedule commands to run after a
 * given delay, or to execute periodically.
 * @param corePoolSize the number of threads to keep in the pool,
 * even if they are idle.
 * @return a newly created scheduled thread pool
 * @throws IllegalArgumentException if {@code corePoolSize < 0}
 */

这意味着int参数是“核心池大小”。核心是这里的关键词。如果您深入到实现,它实际上使用您在代码段中调用的相同方法,因此实际上没有更改。 我在这里省略了一点,但“核心”池大小是池中保持活动的最小线程数(一旦启动它们,池通常不会抢先创建线程,但是这是实施,而不是我记得的合同)。这与最大线程数无关。 实际上,如果你进一步向下钻取,你会发现你使用的构造函数最终将构建一个无限的池,可以根据需要生成尽可能多的线程。

因此,您提交到池中的作业可能会同时执行。如果您需要单线程池,则可能需要使用Executors.newSingleThreadedScheduledExecutor工厂方法。

最后,您的工作取消需求。那么如何取消已经汇总的工作呢?好吧,当你提交一份工作时,ExecutorService个实例通常会给你一个Future个对象。 此Future对象具有嵌入的取消逻辑。它允许您在提交的作业上设置取消标志(如果尚未启动它将阻止它正常运行),如果它已经启动,也可以激活线程中断。

希望这有点澄清了语义。