Android:简单的时间计数器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11730902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:37:19  来源:igfitidea点击:

Android: simple time counter

androidtimer

提问by DavidNg

I have a simple program with one TextView and two Buttons: Button1 and Button2.

我有一个简单的程序,其中包含一个 TextView 和两个按钮:Button1 和 Button2。

Clicking on Button 1 will start a counter, increasing by 1 every 1 second and show result on TextView; clinking on Button 2 will stop it. Here is a part of my code for Button1. But it does not work.

单击按钮 1 将启动一个计数器,每 1 秒增加 1 并在 TextView 上显示结果;碰上按钮 2 将停止它。这是我的 Button1 代码的一部分。但它不起作用。

    Timer T=new Timer();
    T.scheduleAtFixedRate(new TimerTask() {         
            @Override
            public void run() {
                myTextView.setText("count="+count);
                count++;                
            }
        }, 1000, 1000);

I know that there are some similar questions about this using Thread but it seems like they do not mention about stopping the counter.

我知道使用 Thread 有一些类似的问题,但似乎他们没有提到停止计数器。

Any suggestion is really appreciated.

任何建议都非常感谢。

Added:

添加:

Hello, I just shortened my code just to this from a much bigger program, but it is still crashed:

你好,我刚刚从一个更大的程序中将我的代码缩短到这个,但它仍然崩溃了:

package com.example.hello;
import java.util.Timer;
import java.util.TimerTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {
    TextView myTextView;
    int count=0;
    Timer T;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myTextView=(TextView)findViewById(R.id.t);
        T=new Timer();
        T.scheduleAtFixedRate(new TimerTask() {         
            @Override
            public void run() {
                myTextView.setText("count="+count);
                count++;                
            }
        }, 1000, 1000);       
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}

The log file (I do not want to post this because it is too long but someone requested it):

日志文件(我不想发布它,因为它太长但有人要求它):

07-28 17:35:07.012: W/dalvikvm(11331): threadid=7: thread exiting with uncaught exception (group=0x4001d800)
07-28 17:35:07.016: E/AndroidRuntime(11331): FATAL EXCEPTION: Timer-0
07-28 17:35:07.016: E/AndroidRuntime(11331): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.view.ViewRoot.checkThread(ViewRoot.java:2802)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.view.ViewRoot.requestLayout(ViewRoot.java:594)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.view.View.requestLayout(View.java:8125)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.view.View.requestLayout(View.java:8125)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.view.View.requestLayout(View.java:8125)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.view.View.requestLayout(View.java:8125)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:254)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.view.View.requestLayout(View.java:8125)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.widget.TextView.checkForRelayout(TextView.java:5378)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.widget.TextView.setText(TextView.java:2688)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.widget.TextView.setText(TextView.java:2556)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at android.widget.TextView.setText(TextView.java:2531)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at com.example.hello.MainActivity.run(MainActivity.java:21)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at java.util.Timer$TimerImpl.run(Timer.java:289)

回答by Pavel Dudka

You can introduce flag. Something like isPaused. Trigger this flag whenever 'Pause' button pressed. Check flag value in your timer task. Success.

您可以引入标志。类似的东西isPaused。每当按下“暂停”按钮时触发此标志。检查计时器任务中的标志值。成功。

Timer T=new Timer();
T.scheduleAtFixedRate(new TimerTask() {         
        @Override
        public void run() {
            runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    myTextView.setText("count="+count);
                    count++;                
                }
            });
        }
    }, 1000, 1000);


 onClick(View v)
 {
      //this is 'Pause' button click listener
      T.cancel();
 }

回答by hovanessyan

Chekout thisexample, that uses the Chronometerclass: http://android-er.blogspot.com/2010/06/android-chronometer.html

Chekout这个例子,它使用Chronometer类:http: //android-er.blogspot.com/2010/06/android-chronometer.html

Using the Chronometer class will save you managing the thread yourself.

使用 Chronometer 类将节省您自己管理线程的时间。

回答by Giedrius ?likas

Perfect solution if you want to display running clock.

如果你想显示运行时钟,完美的解决方案。

private void startClock(){
    Thread t = new Thread() {

        @Override
        public void run() {
            try {
                while (!isInterrupted()) {
                    Thread.sleep(1000);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Calendar c = Calendar.getInstance();

                            int hours = c.get(Calendar.HOUR_OF_DAY);
                            int minutes = c.get(Calendar.MINUTE);
                            int seconds = c.get(Calendar.SECOND);

                            String curTime = String.format("%02d  %02d  %02d", hours, minutes, seconds);
                            clock.setText(curTime); //change clock to your textview
                        }
                    });
                }
            } catch (InterruptedException e) {
            }
        }
    };

    t.start();
}

回答by Andy

Pavel is on the right track with stopping it, except his answer is a waste since it doesn't stop the Timer. Do this on the part he posted with the added else statement:

Pavel 是在正确的轨道上停止它,但他的回答是浪费,因为它没有停止计时器。在他发布的带有添加 else 语句的部分执行此操作:

if(!isPaused)
        {
            myTextView.setText("count="+count);
            count++;                
        } else {
            cancel();//adding this makes it actually stop
        }

Oh and you said it crashed. We have no idea why it's crashing, so unfortunately we cannot really help figuring out why its doing that unless we see more code and the error.

哦,你说它崩溃了。我们不知道它为什么会崩溃,所以不幸的是,除非我们看到更多的代码和错误,否则我们无法真正帮助弄清楚它为什么会崩溃。

Good catch @yorkw The problem is obviously with something its trying to do when its starts running. Since its says "Timer-0", this means it never starts officially and it gets stuck in that part. First rule of running threads, NEVER CHANGE UI ELEMENTS FROM OUTSIDE THE UI. I would suggest using runOnUiThreadlike york said. Here's a link on how to use it: runOnUiThread. Pretty sure TimerTaskis a runnable meaning it runs on a separate thread. Least thats what I noticed on the docs.

很好的捕获@yorkw 问题显然在于它开始运行时试图做的事情。因为它说“Timer-0”,这意味着它永远不会正式启动,并且卡在那个部分。运行线程的第一条规则,永远不要从 UI 外部更改 UI 元素。我建议runOnUiThread像约克说的那样使用。这是有关如何使用它的链接:runOnUiThread。很确定TimerTask是可运行的,这意味着它在单独的线程上运行。至少这就是我在文档中注意到的。

回答by Gean Carlos Brand?o

This way it is much simpler. It is a feature made available on the android developer site. Link

这样就简单多了。这是 android 开发者网站上提供的一项功能。关联

public void initCountDownTimer(int time) {
    new CountDownTimer(30000, 1000) {

        public void onTick(long millisUntilFinished) {
            textView.setText("seconds remaining: " + millisUntilFinished / 1000);
        }

        public void onFinish() {
            textView.setText("done!");
        }
    }.start();
}

回答by thando

As @hovanessyansuggested: You can use the Chronometerclass. E.g., as follows (with Kotlin, Java analog):

正如@hovanessyan建议的那样:您可以使用Chronometer类。例如,如下(使用 Kotlin,Java 模拟):

class ChronometerToggler: Fragment() {
    private lateinit var chronometer: Chronometer
    private var isChronometerRunning = false
    private lateinit var toggleButton: FloatingActionButton

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.my_layout, container, false)
        chronometer = view.findViewById(R.id.chronometer)
        toggleButton = view.findViewById(R.id.toggle_button)
        toggleButton.setOnClickListener {
            onToggleButtonPressed()
        }
        return view
    }

    private fun onToggleButtonPressed() {
        isChronometerRunning = !isChronometerRunning
        if (isChronometerRunning) {
            chronometer.base = SystemClock.elapsedRealtime()
            chronometer.start()
        }
        else {
            chronometer.stop()
        }
    }
}

In the my_layout.xml:

my_layout.xml

[...]
     <Chronometer android:id="@+id/chronometer" [...]/>
[...]