【问题标题】:Starting Two (or More) Functions Simultaneously in Android在 Android 中同时启动两个(或更多)功能
【发布时间】:2012-11-20 12:47:57
【问题描述】:

我正在为 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);
    }
}

虽然计时器和计时器上的秒数看起来是同步的最初,但在很短的时间之后,它们似乎会消失,并且两者的第二次更新发生在不同的时间。

想知道我能做些什么来解决这个问题。我确实遇到过 - 并阅读了这个帖子

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

我意识到可能需要进行设计更改,但我不确定具体需要做什么。

编辑:包括计时器和计时器的类型以及使用 Chronometer 计算时间的方法 - 根据 jolivier 和 njzk2 的建议

【问题讨论】:

  • 你的 mChronometer 和 mCounter 是什么?你如何测量时间?
  • 你为什么使用小部件而不是 System.nanoTime() 或 currentTimeMillis() ?
  • @Shark,不确定我是否知道您的问题的答案。谢谢。

标签: android timer chronometer


【解决方案1】:

您可以使用 System.currentTimeMillis() 检索当前时间,将其存储到变量中并将其转发给mChronometermCounter,以便它们使用相同的时间参考,尽管它们的任务开始于不同的时间。

编辑:使用给定的类型,android documentation about Chronometer 会告诉您可以使用elapsedRealTime 来实现我所说的。 CountDownTimer 没有这个,它的 start 方法是最终的,所以你可能想要使用另一个实现,更好地了解你的用例可能会对我们有所帮助。

基本上,希望两个线程在同一毫秒执行一个动作绝不是一个好主意,其中一个将用作时钟,另一个必须是从属并监听时钟。

【讨论】:

  • 感谢您的回答。当您说存储在变量中的值需要转发到mChronometermCounter 时,我不确定我是否遵循您的意思。我确实看过mChronometer.start()mCounter.start() 方法,但看起来它们不接受初始值(使用System.currentTimeMillis() 可以获得并存储在那里)。所以,换句话说,没有像mChronometer.start(initialVal)mCounter.start(initialVal) 这样的东西。还是我误解了你的建议?
  • 你能在你的问题中给出 mChronometer 和 mCounter 的类型吗?我需要它来帮助你
  • @njzk2 刚刚添加了一些代码以使事情变得清晰。谢谢。
  • @njzk2 增加了清晰度以显示如何计算时间。另外,我确实根据您指向的文档使用elapsedRealTime。谢谢。
  • 我对此进行了更多思考,但仍然没有明确的前进方向。我可以改变什么,让一个是主人,一个是奴隶?那么,这是否需要自定义实现计时器或计时器?假设 chronometer 实现被保留并被认为是主设备,那么计时器如何成为从设备?
【解决方案2】:

所以,在考虑了一段时间并放弃了jolivier 如此慷慨地与我们分享的建议之后,我意识到存在一种名为onChronometerTick 的方法,每次有计时器滴答时都会调用它(每秒, 在这种情况下)。所以,我想每次调用该方法时从计数器中减去 1000 毫秒,并相应地更新计时器显示。我完全摆脱了 Android 计时器 (CountDownTimer)。我认为这将是同时更新两个显示器的好方法。它也是一个简单的计时器实现。

我很高兴地报告它似乎运作良好。计时器和计时器显示确实同时更新。所以,原来的问题看起来已经回答了。不幸的是,我在计时器前面遇到了一个错误的错误,我用一个丑陋的黑客修复了这个错误。我正在发布到目前为止的内容。欢迎任何有关如何修复黑客或改进代码的建议。请注意,我已对代码进行了注释,以使其易于理解所做的工作。

修改错误:我注意到的另一件事是,大约 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
    ...
}

【讨论】:

  • 这就是我说的只使用一个时钟线程并让所有时间逻辑依赖于它的意思。您的 hack 可能来自这样一个事实,即当您在计时器上调用 start() 时调用了 ChronometerListener。有关此侦听器的文档非常不完整,您的代码假定它每秒调用一次,但它可能会被更频繁地调用,当它真正被调用时,您可能希望在此代码之外进行测试。
  • 哇!谢谢你。我很感谢您的建议,并且很高兴实施或多或少是您的意思。 onChronometerTick 是对的 - 看起来它被调用了两次 - 但只有当 mChronometer.start() 被调用时。之后,它似乎每秒只被调用一次。奇怪的。我想知道如何优雅地解决这个问题。
  • 我开始了一个新线程,专注于这里遇到的两个错误。看起来“onChronometerTick”可能是罪魁祸首。更多详情请见stackoverflow.com/questions/13523804/…
猜你喜欢
  • 1970-01-01
  • 2021-01-31
  • 1970-01-01
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-07
相关资源
最近更新 更多