2012-11-20 15 views
5

Android 2.2のクロノメーター/カウントダウンタイマーアプリを設計中です。ボタンを1回押すと、クロノメーターが同時に起動します。ですから、理想的には、秒(時間)をに入れてください。クロノメーターとタイマーを同じインスタンスで変更してください。 (タイマーは、クロノメーターがカウントアップしている間もカウントダウンします)。私は、Androidが提供するクロノメーターとタイマー機能を使用していますので、それはであるクロノメーターとタイマーの秒のように見えますが、ユーザが「スタート」ボタンAndroidで同時に2つ以上の機能を開始する

private boolean mStartPressedOnce = false; 
long mTimeWhenStopped = 0; 
Chronometer mChronometer; 
MyCounter mCounter; 
... 
@Override 
public void onClick(View v) { 
    switch (v.getId()) { 
    case R.id.StartButton: 
     // Perform some initialization for the chronometer depending 
     // on the button press 
     if (mStartPressedOnce == false) { 
      mChronometer.setBase(SystemClock.elapsedRealtime()); 
     } else { 
      mChronometer.setBase(SystemClock.elapsedRealtime() + mTimeWhenStopped); 
     } 

     // Perform the initialization for the timer 
     mCounter = new MyCount(45000, 1000); 

     // Fire up the chronometer 
     mChronometer.start(); 

     // Fire up the timer 
     mCounter.start(); 
     break; 

     case R.id.ResetButton: 
      // Reset the chronometer 
      mChronometer.setBase(SystemClock.elapsedRealtime()); 
      mTimeWhenStopped = 0; 
      break; 

     case case R.id.StopButton: 
      mStartPressedOnce = true; 
      // Stop the chronometer 
      mTimeWhenStopped = mChronometer.getBase() - SystemClock.elapsedRealtime(); 
      mChronometer.stop(); 
      break; 
    } 

... 

public class MyCounter extends CountDownTimer { 

    @Override 
    public MyCount(long millisInFuture, long countDownInterval) { 
     super(millisInFuture, countDownInterval); 
    } 

    @Override 
    public void onFinish() {   
     // Nothing to do here 
    } 

    @Override 
    public void onTick(long millisUntilFinished) { 
     long seconds = (long) (millisUntilFinished/1000); 
     long minutes = (long) ((millisUntilFinished/1000)/60); 
     long hours = (long) (((millisUntilFinished/1000)/60)/60); 

     // Do some formatting to make seconds, minutes and hours look pretty  

     // Update the timer TextView    
     (TextView) findViewById(R.id.CountDownTimerTextView)) 
      .setText(hours + ":" + minutes + ":" + seconds); 
    } 
} 

を押したときに、私は以下のコードを書きました同期が最初にと短時間で消えてしまったように見え、両方の更新が異なる時刻に発生します。

私はこれを解決するために何ができるのだろうかと思っていました。私は必要な設計変更があるかもしれないことを認識しますが、私は実行する必要が正確に何か分からないと

Running multiple AsyncTasks at the same time -- not possible?

このスレッドを読んで - 私が渡って来ました。

編集:クロノメーターを使用して時刻を計算するためのクロノメーターとタイマーや方法について含まタイプ - jolivierとnjzk2の提案ごとに

+2

あなたのmクロノメーターとmCounterは何ですか?どのように時間を測定しますか? – njzk2

+0

なぜSystem.nanoTime()またはcurrentTimeMillis()の代わりにウィジェットを使用していますか? – Shark

+0

@Shark、私はあなたの質問に対する答えを知っているかわからない。ありがとう。 – aLearner

答えて

1

だから、私たちと寛大に共有されているjolivierの提案から離れると、onChronometerTickというメソッドが存在することに気付きました。これは、クロノメーターダニが毎回呼び出されます場合)。だから、メソッドが呼び出されるたびにカウンタから1000ミリ秒を引いて、それに応じてタイマー表示を更新することを考えました。私はAndroidのタイマーの部分(CountDownTimer)を完全に取り除いた。私はこれが両方のディスプレイを同時にアップデートする良い方法だと考えました。タイマーの簡単な実装です。

私はそれがうまくいくと思われることを報告しています。タイマーとクロノメーターの両方が同時に更新されます。それで、元の質問はそれが答えられたように見えます。残念なことに、私は醜いハックで修正したタイマーのフロントでoff-by-twoエラーに遭遇しました。私はこれまでのことを投稿しています。ハックを修正する方法やコードを改善する方法に関する提案は大歓迎です。何が行われたのかを簡単に理解できるようにコードにコメントしました。

バグの編集:私が気づいたもう一つの事は、約10分後にクロノメーターとタイマーが1秒遅れていることです。より正確には、タイマーはクロノメーターの後ろに1秒間あります。なぜこれが起こるのかはまだ分かりません。

private boolean mStartPressedOnce = false; 
long mTimeWhenStopped = 0; 
Chronometer mChronometer; 
long millisUntilFinished = 0; 
boolean firstPassOver = false; 
int counter = 0; 
... 
@Override 
public void onClick(View v) { 
    switch (v.getId()) { 
    case R.id.StartButton: 
     // Perform some initialization for the chronometer depending 
     // on the button press 
     if (mStartPressedOnce == false) { 
      mChronometer.setBase(SystemClock.elapsedRealtime()); 
     } else { 
      mChronometer.setBase(SystemClock.elapsedRealtime() + mTimeWhenStopped); 
     } 

     // Fire up the chronometer 
     mChronometer.start(); 
     break; 

     case R.id.ResetButton: 
      // Reset the chronometer 
      mChronometer.setBase(SystemClock.elapsedRealtime()); 
      mTimeWhenStopped = 0; 
      break; 

     case case R.id.StopButton: 
      mStartPressedOnce = true; 
      // Stop the chronometer 
      mTimeWhenStopped = mChronometer.getBase() - SystemClock.elapsedRealtime(); 
      mChronometer.stop(); 
      break; 
    } 

... 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.stop_watch); 

    mChronometer = (Chronometer) findViewById(R.id.StopWatchTextView); 

    // Initialize the number of milliseconds before the timer expires (
    // set the timer) - in this case to 46 seconds 
    millisUntilFinished = 46000; 

    // Display how many seconds remain before the timer expires 
    ((TextView) findViewById(R.id.CountDownTimerTextView)).setText(hours 
      + ":" + minutes + ":" + millisUntilFinished/1000); 

    // In line with the suggestion provided by jolivier - make the timer 
    // the slave and update its display every time the chronometer 
    // ticks   
    mChronometer 
      .setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() { 

       @Override 
       public void onChronometerTick(Chronometer chronometer) { 

        // Update the display for the chronometer 
        CharSequence text = chronometer.getText();     
        chronometer.setText(text); 

        // Update the display for the timer     
        // !!! BUG !!! 
        // Looks like onChronometerTick is called at the 0th second 
        // and this causes an off by two error if a count down timer 
        // is being implemented. Fixed it with this hack. There's gotta 
        // be a more elegant solution, though. 
        if(counter >= 2) { 
         millisUntilFinished1 = millisUntilFinished1 - 1000; 
         counter = 2; 
        } 
        counter++; 

        if (millisUntilFinished >= 0) { 

         long seconds = (long) (millisUntilFinished/1000); 
         long minutes = (long) ((millisUntilFinished/1000)/60); 
         long hours = (long) (((millisUntilFinished/1000)/60)/60); 

         // Do some formatting to make seconds, minutes and hours look pretty  

         // Update the timer TextView  
         ((TextView) findViewById(R.id.CountDownTimerTextView)) 
           .setText(hours + ":" + minutes + ":" 
             + seconds); 
         } 
        } 

    }); 
    // Other code 
    ... 
} 
+1

それは確かに私はクロックのための1つのスレッドを使用し、すべての時間のロジックはそれに依存することを意味するものです。あなたのハックは、クロノメーターで '' start() ''を呼び出すときに '' ChronometerListener''が呼び出されるという事実から来るかもしれません。このリスナーに関するドキュメントは非常に不完全であり、コードは毎秒呼び出されると仮定していますが、より頻繁に呼び出すことができます。実際に呼び出されたときにこのコードの外側でテストしたいことがあります。 – jolivier

+0

うわー!ありがとうございました。私はあなたの提案に感謝し、実装が多かれ少なかれあなたが意味するものであることを嬉しく思っています。あなたは 'onChronometerTick'について正しいです - それは2回呼ばれるように見えますが、' mChronometer.start() 'が呼び出されたときだけです。その後、1秒に1回だけ呼び出されるようです。奇妙な。私はこの問題に対するエレガントな修正が何であるか疑問に思います。 – aLearner

+0

私はここで遭遇した2つのバグに焦点を当てるために新しいスレッドを開始しました。 'onChronometerTick 'は責任があるようです。詳細については、http://stackoverflow.com/questions/13523804/onchronometertick-called-two-times-before-chronometer-value-changesを参照してください。 – aLearner

2

あなたは、にSystem.currentTimeMillis()で現在の時刻を取得し、変数にそれを保存することができますし、 mChronometermCounterの両方に転送します。そのため、タスクは異なる時刻に開始されましたが、同じ時間参照を使用します。

編集:指定した種類のandroid documentation about Chronometerは、私が言ったことを達成するためにelapsedRealTimeを使用できることを教えてくれます。 CountDownTimerにはこれがなく、そのstartメソッドがfinalであるため、別の実装を使用することもできます。ユースケースをよく見れば役立ちます。

基本的には、同じミリ秒でアクションを実行する2つのスレッドが良いアイデアはありません。そのうちの1つはクロックとして機能し、もう1つはスレーブでクロックを聴く必要があります。

+0

あなたの答えをありがとう。変数に格納されている値が 'mクロノメーター'と 'mCounter'に転送される必要があると言ったときに、私があなたが何を意味するのかはわかりません。私は 'mChronometer.start()'と 'mCounter.start()'メソッドを見ましたが、初期値( 'System.currentTimeMillis()'を使って得られたもの)を受け入れずに保存されているようですそこ)。つまり、 'mChronometer.start(initialVal)'や 'mCounter.start(initialVal)'のようなものはありません。それとも私はあなたの提案を誤解しましたか? – aLearner

+0

あなたの質問にmクロノメーターとmCounterのタイプを教えていただけますか? – jolivier

+0

@ njzk2もっと分かりやすいコードを追加しました。ありがとうございました。 – aLearner

関連する問題