Android: simple time counter

2020-02-03 10:20发布

问题:

I have a simple program with one TextView and two Buttons: Button1 and 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.

    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.

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

回答1:

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

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


回答2:

Chekout this example, that uses the Chronometer class: http://android-er.blogspot.com/2010/06/android-chronometer.html

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



回答3:

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


回答4:

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:

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 runOnUiThread like york said. Here's a link on how to use it: runOnUiThread. Pretty sure TimerTask is a runnable meaning it runs on a separate thread. Least thats what I noticed on the docs.



回答5:

This way it is much simpler. It is a feature made available on the android developer site. 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();
}


回答6:

As @hovanessyan suggested: You can use the Chronometer class. E.g., as follows (with Kotlin, Java analog):

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:

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


标签: android timer