2016-11-14 9 views
1

私はアンドロイドスタジオで簡単なゲームを作ろうとしており、特定のイベントを遅らせる必要があります。Javaで遅延イベントを処理する最良の方法は何ですか

私はいくつかのグーグルを行うことから始め、TimerTimerTaskがかなり良い選択肢であることがわかりました。しかし、私の活動がに電話した場合、Timer.pauseはありません。私はすべてをキャンセルする必要があります。

私は、私のためのイベントを処理し、一時停止をサポートする自分のクラスを作成することに決めました。

私はSystem.currentTimeMillis> = eventFinishedTimeかどうかを確認するために10ミリ秒ごとのイベントのArrayListを通じて簡単なユーザコマンドに「イベント(複数可)」を作成したクラス(EventHandler)、およびサイクルを作りました。イベントが完了すると、intefaceメソッドが呼び出され、イベントはArrayListから自身を削除します。

今、私は新しい問題にぶつかります。

EventHandlerは、イベントが終了したときにインターフェイスメソッド(onFinished)を呼び出します。したがって、onFinishedで最後に宣言されていない変数は使用できません。私が見つけることができるこの周りの唯一の方法は、イベントを遅らせるたびに新しい方法を作ることです。これは悪い習慣のようです。

私の質問は、これを行うにはどうすればよいですか、それともどうしますか?

は、あなただけの参考詳細は、お気軽にどの部分:) 指定し、私のコードを見たい場合は尋ねること自由に感じ...私はかなりを総括し、しようとする意思よりも午前さらに例を挙げて説明してください。

ありがとうございます!ここで

はEventHandler.class(私は輸入品が含まれていませんでした...インターフェイスメソッドが呼び出された場所を確認するために一番下までスクロール)である:私はそれを使用しようとするのはここ

public class EventHandler extends Thread { 
    //Constants 
    final String TAG = "EventHandler"; 
    final long WAIT_TIME = 10; 


    public ArrayList<Event> events = new ArrayList<>(); //Every WAIT_TIME the run() funtion cycles through this list and checks if any events are complete 
    public boolean runChecks = true; //If true, the run() function goes (It's only false while the DoDayActivity tells it to pause 
    public long pauseStartTime; //This value tags the System.currentTimeMillis() @pauseCheck 
    public long totalPausedTime = 0; //This value contains how long the EventHandler was paused 
    Activity activity; 

    public EventHandler(Activity activity) { 
     this.activity = activity; 
    } 

    public void run() { 
     //checking the listeners 
     while (true) { 
      if (runChecks) {//Making sure the timer isn't paused 
       checkListeners(); 
      } 
      try { 
       Thread.sleep(WAIT_TIME); //Yes I am using Thread.sleep(), kill me 
      } catch (Exception ignore) { 
      } 
     } 

    } 

    public interface OnEventListener { 
     void onFinished(); 
    } 


    public void createEvent(String name, long milliseconds, OnEventListener eventListener) {//This is how an event is created, see the private Event class below 
     new Event(this, name, milliseconds, eventListener); 
    } 

    public void checkListeners() { 
     for (Event event : events) { 
      event.amIFinished();//A method that checks if the event has reached its end time 
     } 
    } 

    public void pauseCheck() { //"Pauses" the timer (Probably not the best way, but it is simple and does what I need it to 
     runChecks = false; 
     pauseStartTime = System.currentTimeMillis(); 
    } 

    public void resumeCheck() {//Resumes the timer by adding the amount of time the EventHandler was paused for to the end if each event 
     try { 
      if ((pauseStartTime > 99999999)) {//For some reason, when an activity is created, onResume is called, so I added this in there to prevent glicthes 
       totalPausedTime = System.currentTimeMillis() - pauseStartTime; 
       Log.d(TAG, "Resuming, adding " + String.valueOf(totalPausedTime) + " milliseconds to each event"); 
       for (Event e : events) { 
        e.end += totalPausedTime; 
       } 
      } 
     } catch (Exception e) { 
      Log.w(TAG, "During resume, EventHandler tried to add time to each of the events, but couldn't!"); 
      e.printStackTrace(); 
     } 

     runChecks = true; 

    } 


    private class Event { //Here is the class for the event 
     public long start; 
     public long end; 
     OnEventListener listener; 
     EventHandler parent; 
     String name; 

     public Event(EventHandler parent, String name, long milliseconds, OnEventListener listener) { 
      start = System.currentTimeMillis(); 
      end = start + milliseconds; 
      this.listener = listener; 
      this.parent = parent; 
      this.name = name; 

      //Adding itself to the ArrayList 
      parent.events.add(this); 
     } 

     public void amIFinished() {//Method that checks if the event is completed 
      if (System.currentTimeMillis() >= end) {//Removes itself from the arraylist and calls onFinished 
       Log.d(TAG, "Completed " + name); 
       parent.events.remove(this); 
       activity.runOnUiThread(new Runnable() { 
        @Override 
        public void run() { 
         listener.onFinished(); //This is where the interface method is called! 
        } 
       }); 
      } 
     } 
    } 
} 

です(これがint xを使用して単なる例です):

int x = 0; 

eventHandler = new EventHandler(this); 
eventHandler.start(); 
eventHandler.createEvent("Change X Value", 800, new EventHandler.OnEventListener() { 
    @Override 
    public void onFinished() { 
     //x is not declared final so it will not work 
     x = 5; 

    } 
}); 
+0

ポストを更新しました – Pythogen

+0

cuncurrent programmで 'ArrayList'を使用しないでください。別のクラス 'CopyOnWriteArrayLis'、' ConcurrentLinkedQueue'、...を参照してください。 –

答えて

1

それは効果的に、最終的にする必要がある唯一の参照です。それは内部クラスからオブジェクトの状態を変更するにはOKです:

AtomicInteger x = new AtomicInteger(0); 

eventHandler = new EventHandler(this); 
eventHandler.start(); 
eventHandler.createEvent("Change X Value", 800, new EventHandler.OnEventListener() { 
    @Override 
    public void onFinished() { 
     // x is effectively final so we can reference it 
     x.set(5); 
    } 
}); 

それとも...私はそれをやっていた場合は、ラムダ

eventHandler.createEvent("Change X Value", 800,() -> x.set(5)); 

を使用して、私は抽象的なゲームタイムラインを思います。メインループ内ののティックカウンターを増加させて、リアルタイムではなくゲーム時間に応じてイベントを処理します。

イベントは、ゲーム時間でソートされたツリーセットにイベントを追加してスケジューリングすることができ、セットから引き出され、期限が切れたときにメインループによって実行されます。

+0

ゲームのタイムラインを抽象化することについての非常に面白いアイデアですが、スケジュールされたイベントを引き出して実行できると言うと、私の現在の問題にぶち込まずに何を実行するか。あなたはたぶんこのことについてどういうふうに例を挙げたり、リンクを参照したりできますか?これは良いルートのようです。 – Pythogen

+0

@Pythogen:これを見つけました... http://gameprogrammingpatterns.com/game-loop.html – teppic

0

私はあなたが達成しようとしているかを正確にわからないんだけど、あなたはScheduledExecutorServiceに興味がある可能性がありようですね。これにより、将来特定の時間に再生されるRunnablesまたはCallablesを送信することができます。また、イベントが終了すると自動的にQueueから自分自身を削除します。

0

これはAndroidなので、onPause呼び出し後にアプリケーションがメモリから完全には削除されないことを確認することはできません。だから、最善の方法はScheduledExecutorServiceのようなものを使うことです。 onPauseイベントが発生したときにスケジュールされたRunnableをキャンセルします。 onResumeが呼び出されたら、同じRunnableを再度スケジュールするだけです。

それ以外の場合は、Androidのアプリケーションモデルに問題が発生する可能性があります。一時停止状態のアプリケーションはメモリから削除できます。したがって、カスタムタイマーの保存状態を実装する必要があります。

+0

良い点ですが、幸いにも、ユーザーがアプリを本当に素早く切り替えるための一時停止機能が必要です。ボタンなどがあります。アプリケーションがリサイクルされた正確な時刻から再開する必要はありません。ゲームに保存されているチェックポイントがあるためです。 – Pythogen

関連する問題