2013-03-07 59 views
0

這是我第一次真正涉足Android編程,但我覺得我有更多的Java問題 - 對ScheduledThreadPoolExecutor如何工作的一些重大誤解(雖然我願意以表示這是AnimatedSprites的AndEngine問題)。實質上,我希望精靈在發生碰撞之前一動不動。精靈動畫,並在一秒鐘後,再次停止。用戶必須保持Flinging以「游泳」水中的精靈。我遇到的問題是動畫。如果您在1秒的時間範圍內有多個Fling,則動畫僅在停止前顯示一幀或兩幀,感覺像「停止動畫」任務正在堆疊。我會檢查並確保在我完成所有這些工作後Flings足夠長並且朝着正確的方向。當我第一次實例化ScheduledThreadPoolExecutor時,我提供的池大小爲1,這對我來說意味着它一次不能有超過一個任務在隊列中。最重要的是,在我調用.schedule()之前,我將.remove()任務,以確保沒有任何內容。我確信這是簡單的,只是我對如何正確使用這個問題有一些誤解。我將在這裏粘貼相關代碼部分:使用ScheduledThreadPoolExecutor重複安排AndEngine的任務

... 

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; 
} 

回答

0

這個問題涉及到一個棘手的問題。 作爲第一條評論,我想強調的是,在處理ExecutorService時,您應該堅持編碼到接口而不是實現。這應該可以避免你想要做的一些複雜的事情。

例如,您提到使用remove()方法,該方法在(Scheduled)ExecutorService接口中是公開的但不存在。這意味着使用這可能需要您可能無法完全控制的某些實現特定行爲。

從remove方法的Javadoc,對ThreadPoolExecutor

/** 
* 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對象具有嵌入的取消邏輯。它允許您在提交的作業上設置一個取消標誌(如果它尚未啓動,將會阻止其執行),並且如果它已經啓動,還可能導致線程中斷。

希望這已經澄清了一下語義。

+0

哇,這麼多隻是一個簡單的誤解。我希望有一個「哦,你忘了......」這是一個很好的解釋,我很欣賞你投入的時間。看起來我有一些閱讀要做 - 執行者顯然不像我以爲他們做的那樣工作。 – NickGlowsinDark 2013-03-07 19:39:53