2011-03-03 3 views
1

아래 나는 초당 한 번 '시계'레이블을 업데이트하는 스레드가 있습니다. 스레드가 600 (10 분)에 도달하면 타이머가 중지됩니다. 스레드는 매분 약 5 초 정도 걸립니다. 따라서 val = 60 일 때 실제로 65 초가 경과했을 수 있습니다. 나는 midp를 사용하고 있는데, 나는이 일을 도와 줄 어떤 api도 소개 할 수 없다고 생각한다. 수업의 정확성을 어떻게 향상시킬 수 있습니까? 나는 그것을 감속시키는 것이 convertValToTimerString 메서드라고 생각한다. 현재 타이머 val을 분으로 변환하는 더 좋은 방법이있다 : java formatter apis를 사용하지 않고 초 형식을 사용 하는가?내 타이머 스레드의 정확도 향상

감사합니다,

public class LabelTimerUpdaterThread implements Runnable{ 

    public static int val = 0; 
    private int minuteValueInt = 0; 
    private int secondValueInt = 0; 
    private int tempSecondValueInt; 
    public boolean isRunning = true; 

    public LabelTimerUpdaterThread(){ 

    } 

    public void run() { 
     while(isRunning){ 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      val += 1; 


      incrementTimer(); 

      if(val == 600){ 
       break; 
      } 
     } 
    } 

    private void incrementTimer(){ 
     Screen.timerLabel.setText(convertValToTimerString(val)); 
    } 

    private String convertValToTimerString(int val){ 

     String minuteValString = ""; 
     String secondValString = ""; 

     if(val < 10){ 
      minuteValString = "00"; 
      secondValString = "0"+String.valueOf(val); 
      return minuteValString+":"+secondValString; 
     } 

     if(val < 60){ 
      minuteValString = "00"; 
      secondValString = String.valueOf(val); 
      return minuteValString+":"+secondValString; 
     } 

     if(val % 60 == 0){ 
      ++minuteValueInt; 
     } 

      if(minuteValueInt < 10){ 
       minuteValString = "0"+String.valueOf(minuteValueInt); 
       int secondVal = val % 60; 
       if(secondVal < 10){ 
        return minuteValString+":0"+String.valueOf(secondVal); 
       } 
       else { 
        return minuteValString+":"+String.valueOf(secondVal); 
       } 
      } 

     return "10:00"; 
    } 

    public void stopThread(){ 
     this.isRunning = false; 
    } 

좋아, 내 타이머 라벨 upedate 할 때 지금은 IllegalStateException가 수신하고 - 여기 것은 내 코드 -

- 여기

내가 내 레이블을 인스턴스화하고

timerLabel = new CustomLabelField("00:00" , Field.FIELD_LEFT , Constants.SMALL_FONT , Color.BLACK, Bitmap.getBitmapResource("bg_clock_white.png")); 

UpdateValTimer timer = new UpdateValTimer(th); 
timer.startTimer(); 

이 클래스는 타이머 클래스를 만들고 타이머 레이블을 업데이트 할 클래스를 만듭니다.

public class UpdateValTimer { 

    private Timer timer; 
    private int val = 0; 
    private UpdateView uv; 
    private final CustomLabelField customLabelField; 

    public UpdateValTimer(CustomLabelField field) { 
     this.customLabelField = field; 
    } 

    public void startTimer(){ 
     timer = new Timer(); 
     uv = new UpdateView(customLabelField); 
     Thread t = new Thread(uv); 
     t.start(); 

     timer.scheduleAtFixedRate(new TimerTask() { 
      public void run() { 
       ++val;  
      } 
     }, 1000, 1000); 
    } 
} 

이 클래스는 타이머 라벨을 업데이트 - 공용 클래스 UpdateView는 Runnable를 {이 코드가 제대로 작동하는 것 같군 일부 초기 테스트 후 어떤 도움

에 대한

private int val = 0; 
    private int minuteValueInt = 0; 
    private final CustomLabelField timerLabel; 

    public UpdateView(CustomLabelField timerLabel) { 
     this.timerLabel = timerLabel; 
    } 

    public void run() { 
     while(true){ 
      this.timerLabel.setText(convertValToTimerString(this.val)); 
     } 
    } 

    private String convertValToTimerString(int val){ 

      String minuteValString = ""; 
      String secondValString = ""; 

      if(val < 10){ 
       minuteValString = "00"; 
       secondValString = "0"+String.valueOf(val); 
       return minuteValString+":"+secondValString; 
      } 

      if(val < 60){ 
       minuteValString = "00"; 
       secondValString = String.valueOf(val); 
       return minuteValString+":"+secondValString; 
      } 

      if(val % 60 == 0){ 
       ++minuteValueInt; 
      } 

       if(minuteValueInt < 10){ 
        minuteValString = "0"+String.valueOf(minuteValueInt); 
        int secondVal = val % 60; 
        if(secondVal < 10){ 
         return minuteValString+":0"+String.valueOf(secondVal); 
        } 
        else { 
         return minuteValString+":"+String.valueOf(secondVal); 
        } 
       } 

      return "10:00"; 
     } 

} 

감사를 구현합니다.

모두에게 도움을 주셔서 감사합니다.

내가 더 잘할 수있는 것에 대한 의견은 환영합니다. 바로 실행 가능한 상태가 immediatelly 실행을 보장하지 않는, 그것은 그냥 그것으로 돌아 오기 그 후

public class UpdateValTimer{ 

    private int minuteValueInt = 0; 
    private Timer timer; 
    private int val = 0; 
    private UpdateView uv; 
    private CustomLabelField customLabelField; 

    public UpdateValTimer(CustomLabelField field) { 
     this.customLabelField = field; 
    } 

    public void startTimer(){ 
     timer = new Timer(); 
      uv = new UpdateView(customLabelField); 
      Thread t = new Thread(uv); 
      t.start(); 

     timer.scheduleAtFixedRate(new TimerTask() { 
      public void run() {    
       ++val;  
       uv.setVal(convertValToTimerString(val)); 
      } 
     }, 1000, 1000); 


    } 

    private String convertValToTimerString(int val){ 

      String minuteValString = ""; 
      String secondValString = ""; 

      if(val < 10){ 
       minuteValString = "00"; 
       secondValString = "0"+String.valueOf(val); 
       return minuteValString+":"+secondValString; 
      } 

      if(val < 60){ 
       minuteValString = "00"; 
       secondValString = String.valueOf(val); 
       return minuteValString+":"+secondValString; 
      } 

      if(val % 60 == 0){ 
       ++minuteValueInt; 
      } 

       if(minuteValueInt < 10){ 
        minuteValString = "0"+String.valueOf(minuteValueInt); 
        int secondVal = val % 60; 
        if(secondVal < 10){ 
         return minuteValString+":0"+String.valueOf(secondVal); 
        } 
        else { 
         return minuteValString+":"+String.valueOf(secondVal); 
        } 
       } 

      return "10:00"; 
     } 
} 


public class UpdateView implements Runnable{ 

    private String timeElapsedCounter; 
    private final CustomLabelField timerLabel; 

    public UpdateView(CustomLabelField timerLabel) { 
     this.timerLabel = timerLabel; 
    } 

    public void setVal(String timeElapsedCounter){ 
     this.timeElapsedCounter = timeElapsedCounter; 
    } 

    public void run() { 

     while(true){ 
     synchronized(Application.getEventLock()){ 
      timerLabel.setText(this.timeElapsedCounter); 
     } 
     } 
    } 

} 


     timerLabel = new CustomLabelField("00:00" , Field.FIELD_LEFT , Constants.SMALL_FONT , Color.BLACK, Bitmap.getBitmapResource("bg_clock_white.png")); 

     UpdateValTimer timer = new UpdateValTimer(timerLabel); 
     timer.startTimer(); 

답변

1

두 가지가 도움이 될 수 있습니다. 우선, incrementTimer() 함수는 convertValToTimerString()을 호출합니다. 언급했듯이, 이것은 약간의 경기 침체를 가져올 것입니다. 그다지 많지는 않지만, 시간이 지남에 따라 이러한 지연은 축적 될 것입니다. 현재 실행 스레드 안에 머물러 있습니다. 해결책은 모델 - 뷰 - 컨트롤러 구성표를 사용하는 것입니다. 모델은 "val"필드입니다. 보기가 레이블입니다. 컨트롤러는 매 초마다이 필드를 업데이트하는 스레드가됩니다. 모델 업데이트를보기 위해 필요한 코드 실행을 분리함으로써 업데이트 스레드가 방해받지 않고 작동 할 수 있습니다.물론 모델의 가치에 따라 라벨의 텍스트를 정기적으로 업데이트하는 방법이 필요합니다. 별도의 스레드가이를 처리 할 수 ​​있습니다.

는 그래서 우리가 가지고있는 것은 :

  • 모델 (귀하의 경우, 단순히 하나 개의 값)
  • 컨트롤러 (모델의 갱신을 대화 형이 아닌 스레드)
  • 뷰 (라벨)
  • 타이머를 사용하여 컨트롤러의 뷰

를 업데이트

  • 스레드는 참으로 오히려 C가의 Runnable을 사용하는 것보다 더 나은 선택이 될 것입니다 alls Thread.sleep(), andersoj가 제안했습니다. TimerTask를 구현해야합니다. 고정 지연에서의 스케줄링과 고정 속도에서의 스케줄링에는 차이가 있습니다. 고정 된 비율은 규칙 성보다 평균 일관성이 더 중요한 작업과 같은 작업에 우선합니다. Timer를 사용한다면, 내가 제안한 위의 모델 - 뷰 - 컨트롤러 구성표는 약간 과잉이다. 라벨 업데이트를 TimerTask의 실행 메소드에 통합 할 수 있습니다. 그러나 그것이 충분히 빨리 일어날 것이기 때문에. 뷰 업데이트에 더 많은 시간이 필요할 경우 (무거운 드로잉이 포함 된 빠른 업데이트의 경우처럼) MVC 패턴은 적절한 분리를 제공하고 사물을 계속 유지합니다.

  • +0

    제 질문이 업데이트되었습니다. 감사합니다. –

    +0

    MVC 원칙을 적절하게 구현 한 것처럼 보입니다. 내가 언급해야 할 한 가지가 있습니다. 레이블을 업데이트하는 것이 단순히 정밀도와 관련하여 스레드와 타이머를 처리하는 방법을 찾는 방법이었던 것처럼 대답했습니다. 그러나 높은 시간 정밀도가 필요한 경우 (즉 정확한 시계가 실제로 필요한 경우), andersoj의 의견이 가장 좋습니다 ... 시스템 시계를 사용하십시오. –

    3
    Thread.sleep(1000); 
    

    적어도 1 초 동안 수면 상태로 스레드를 넣어 것이다 "미래에 언제든지 실행되도록 예약 할 준비가되었습니다". 스레드 스케줄러가 실행될 때까지 스레드 스케줄러에게 달려 있습니다. 예를 들어 실제로 얼마나 많은 시간이 경과했는지 알기 위해 시스템 시간을 확인하는 것이 좋습니다.

    2

    타이머가 필요하면 Timer을 사용하는 것이 좋습니다. 또한 시계를 유지하려면 직접 시도하지 말고 시스템 시계를 샘플링하십시오. 아마 당신이 원하는 것은 사용 currentTimeMillis()