【问题标题】:Android: simple time counterAndroid:简单的计时器
【发布时间】:2021-03-19 05:14:15
【问题描述】:

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

点击按钮 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);

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

非常感谢任何建议。

添加:

您好,我只是将我的代码从一个更大的程序缩短到这个,但它仍然崩溃:

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

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

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$1.run(MainActivity.java:21)
07-28 17:35:07.016: E/AndroidRuntime(11331):    at java.util.Timer$TimerImpl.run(Timer.java:289)

【问题讨论】:

  • 怎么不行?它不应该或不应该做什么或没有做什么
  • 是什么行为导致它不起作用?
  • 为什么不使用 Chronometer?
  • 您能否向我们展示您的所有代码,或者如果您不想全部展示,您愿意展示多少。并在它崩溃时发布你的错误。
  • 点击按钮 2 时只需调用 T.cancel();

标签: android timer


【解决方案1】:

你可以引入flag。像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();
 }

【讨论】:

  • 您发布的内容 - 是源文件。你说它崩溃了——你能从 logcat 发布崩溃日志吗?
  • 我已更新我的代码以避免此崩溃(请参阅runOnUiThread 部分)
  • 为什么需要我在 public void run() 之前删除 @Override 注释?
  • 最后,它适用于您的第二个代码。谢谢,帕维尔。我认为您可以删除第一个代码。
  • 如何检查 T 是否正在运行?因为如果我在开始之前取消计数器,它会给出错误
【解决方案2】:

Chekout this 示例,使用 Chronometer 类:http://android-er.blogspot.com/2010/06/android-chronometer.html

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

【讨论】:

  • 让我试试,它提供停止吗?
  • 是的,它提供停止功能,请参阅 API 文档或链接教程了解更多详细信息。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

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

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

    Kotlin 版本

    fun initCountDownTimer(time: Int) {
    object : CountDownTimer(30000, 1000) {
        override fun onTick(millisUntilFinished: Long) {
            textView.setText("seconds remaining: " + millisUntilFinished / 1000)
        }
    
        override fun onFinish() {
            textView.setText("done!")
        }
    }.start()
    

    }

    【讨论】:

    • 欢迎来到 StackOverflow。尽管代码答案是可以接受的,但您能否添加一些解释,说明为什么您的答案比接受的答案更好?请记住,您的答案将来会被人们阅读,因此您需要添加说明,以便他们理解您的解决方案。
    【解决方案5】:

    Pavel 的停止是正确的,但他的回答是浪费,因为它不会停止 Timer。在他发布的部分执行此操作并添加 else 语句:

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

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

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

    【讨论】:

    • 我做到了。我也没有看到你的错误日志。我们两者都需要。但我也注意到一些事情。应用程序运行时计时器是否启动?
    • 程序永远不会运行。我的安卓有问题?如果我修改为 Thread,它可以正常工作
    【解决方案6】:

    正如@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()
            }
        }
    }
    
    

    my_layout.xml

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-02
      • 2021-03-11
      • 1970-01-01
      相关资源
      最近更新 更多