Запуск двух (или более) функций одновременно в Android

Я в процессе разработки хронометр / таймер обратного отсчета приложение для Android 2.2 и хотел бы одну кнопку нажмите, чтобы начать как хронометр и таймер одновременно. Так что, в идеале, я хотел бы секунды (время) на и хронометр и таймер для изменения в том же экземпляре. (Таймер будет отсчитываться даже как хронометр подсчитывая). Поскольку я использую функциональность хронометра и таймера, предоставляемую Android, я написал следующий фрагмент кода, когда пользователь нажимает кнопку "Пуск"

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

хотя похоже, что секунды на хронометре и таймере синхронизированы изначально, через короткое время они, похоже, отключаются, и вторые обновления для обоих происходят в разное время.

было интересно, что я могу сделать, чтобы исправить это. Я наткнулся-и прочитал эту нить

запуск нескольких AsyncTasks одновременно -- не возможно?

Я понимаю, что может потребоваться изменение дизайна, но я не уверен, что именно нужно сделать.

Edit: включены типы для хронометра и таймера и метод расчета времени с помощью хронометра-per jolivier и предложения njzk2

2 ответов


вы можете получить текущее время с системой.currentTimeMillis (), сохраните его в переменную и перешлите ее в оба mChronometer и mCounter, Так что они используют одну и ту же ссылку времени, хотя их задача началась в разное время.

Edit: с заданными типами,Android документация о хронометре скажу вам, что вы можете использовать elapsedRealTime для достижения того, что я сказал. CountDownTimer не имеет этого и его start метод является окончательным, поэтому вы можете использовать другую реализацию, лучший обзор вашего варианта использования может помочь нам.

В принципе, хотеть, чтобы два потока выполняли действие в одну миллисекунду, никогда не является хорошей идеей, один из них будет служить часами, а другой должен быть рабом и слушать часы.


Итак, поразмыслив над этим некоторое время и отойдя от предложения jolivier так щедро поделился с нами, я понял, что существует метод под названием onChronometerTick который вызывается каждый раз, когда есть ТИК Хронометра (каждую секунду, в этом случае). Итак, я подумал о вычитании 1000 миллисекунд из счетчика каждый раз, когда вызывается метод, и соответствующим образом обновляю отображение таймера. Я избавился от части таймера Android (CountDownTimer) полностью. Я подумал, что это был бы хороший способ имейте оба дисплея update в то же время. Это также простая реализация таймера.

Я рад сообщить, что он, кажется, работает хорошо. И таймер, и хронометр действительно обновляют одновременно. Итак, первоначальный вопрос, похоже, ответили. К сожалению, я столкнулся с ошибкой off-by-two на фронте таймера, которую я исправил с помощью уродливого взлома. Я публикую то, что у меня есть. Любые предложения о том, как исправить Хак или улучшить код приветствуются. Обратите внимание, что у меня есть прокомментировал код, чтобы попытаться сделать его легко понять, что было сделано.

редактировать ошибка: еще одна вещь, которую я заметил, это то, что примерно через 10 минут или около того хронометр и таймер выключены на одну секунду. Точнее, таймер отстает от хронометра на одну секунду. Пока не знаю, почему это происходит.

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