2016-11-14 1 views
1

나는 Android Studio에서 간단한 게임을 만들려고 노력 중이며 특정 이벤트를 지연시킬 수 있어야합니다.Java에서 지연된 이벤트를 처리하는 가장 좋은 방법은 무엇입니까

Google 검색을 시작하면서 TimerTimerTask이 꽤 좋은 옵션 인 것으로 나타났습니다. 그러나 내 활동이 으로 전화 할 경우에는 Timer.pause이 없으므로 모든 것을 취소해야합니다.

그래서 나는 나를 위해 이벤트를 처리하고 일시 중지를 지원하는 자신 만의 클래스를 생성하기로 결정했습니다.

나는 10 밀리 초마다이 경우 System.currentTimeMillis> = eventFinishedTime을보고 이벤트의 ArrayList를 통해 간단한 사용자 명령에 "이벤트 (들)"를 만들어 클래스 ( EventHandler) 및주기를했다. 이벤트가 완료되면 inteface 메서드를 호출하고 이벤트는 ArrayList에서 자신을 제거합니다.

하지만 이제 새로운 문제가 생깁니다.

EventHandler은 이벤트가 완료되면 인터페이스 메서드 (onFinished)를 호출하므로 onFinished에 마지막으로 선언되지 않은 변수를 사용할 수 없습니다. 이 문제를 해결할 수있는 유일한 방법은 사건을 연기하고 싶을 때마다 새로운 방법을 만드는 것입니다. 이는 나쁜 습관처럼 보입니다.

제 궁금한 점은 이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

하는 것은 당신이 내 코드를보고 싶은 경우 단지 은 또한 자세한 내용은 문의 주시기 어느 부분 : 지정, 물어 주시기 바랍니다 ... 나는 꽤 요약하고, 시도 할 의사가 이상 해요 예제와 함께 더 자세히 설명하십시오.

감사합니다. 내가 그것을 사용하려고 경우

다음
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! 
        } 
       }); 
      } 
     } 
    } 
} 

은 다음과 같습니다

(나는 스크롤 인터페이스 방법이라고 볼 수 아래로 수입을 ... 포함하지 않았다)이 EventHandler.class입니다

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

를 사용하여.메인 루프에서 tick 카운터를 증가시키고 실시간이 아닌 게임 시간에 이벤트가 처리 될 때 처리하십시오.

이벤트는 게임 시간별로 정렬 된 TreeSet에 이벤트를 추가하여 스케줄 할 수 있으며, 세트에서 꺼내어 메인 루프가 만기 될 때 실행됩니다.

+0

게임 타임 라인을 추상화하는 것에 대해 매우 흥미로운 생각이 들지만, 예정된 이벤트가 꺼내지고 실행될 수 있다고 말할 때 ... 나는 이벤트를 어떻게 말하는지 정확히 모르겠습니다. 내 현재의 문제에 부딪치지 않고 실행할 것은 무엇인가. 이 문제를 어떻게 해결할 지에 대한 예제와 참고 자료를 줄 수 있습니까? 이것은 좋은 길처럼 보입니다. – Pythogen

+0

@Pythogen :이 사실을 발견했습니다. http://gameprogrammingpatterns.com/game-loop.html – teppic

0

당신이 달성하기 위해 노력하고 정확히 모르겠지만, 당신이 ScheduledExecutorService에 관심이있을 수처럼 소리 : (이것은 INT의 X를 사용하여 단지 예입니다). 이를 통해 향후 특정 시간에 재생할 Runnables 또는 Callables을 제출할 수 있습니다. 또한 이벤트가 완료되면 자동으로 Queue에서 자신을 제거합니다.

0

Android이므로 onPause 호출 후에 응용 프로그램이 메모리에서 완전히 제거되지 않는다는 것을 확신 할 수 없습니다. 따라서 가장 좋은 방법은 ScheduledExecutorService와 같은 것을 사용하는 것입니다. onPause 이벤트가 발생했을 때에, 스케줄 된 Runnable를 취소합니다. onResume이 호출되면 동일한 Runnable을 다시 예약하기 만하면됩니다.

그 외의 경우 Android의 애플리케이션 모델에 문제가 발생할 수 있습니다. 일시 중지 상태의 응용 프로그램은 메모리에서 제거 할 수 있습니다. 따라서 맞춤 타이머의 저장 상태를 구현해야 할 수도 있습니다.

+0

좋은 지적이지만, 다행스럽게도 사용자가 앱을 빠르게 전환하거나 일시 중지하는 경우 일시 중지 기능 만 필요합니다. 버튼 등. 응용 프로그램이 재활용 된 정확한 시간부터 다시 시작할 필요가 없습니다. 게임에 저장된 체크 포인트가 있기 때문입니다. – Pythogen

관련 문제