Android: простой счетчик времени
У меня есть простая программа с одним 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)
Ответы
Ответ 1
Вы можете ввести флаг. Что-то вроде 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();
}
Ответ 2
Chekout этот пример, который использует Chronometer класс: http://android-er.blogspot.com/2010/06/android-chronometer.html
Использование класса Chronometer позволит вам самостоятельно управлять потоком.
Ответ 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
Павел находится на правильном пути, останавливая его, за исключением того, что его ответ пустой, поскольку он не останавливает таймер. Сделайте это в той части, которую он разместил с добавленным выражением else:
if(!isPaused)
{
myTextView.setText("count="+count);
count++;
} else {
cancel();//adding this makes it actually stop
}
О, и ты сказал, что он разбился. Мы не знаем, почему это сбой, поэтому, к сожалению, мы не можем помочь понять, почему это делается, если мы не увидим больше кода и ошибки.
Хороший catch @yorkw Проблема, очевидно, связана с чем-то, что она пытается сделать, когда начинает работать. Поскольку он говорит "Таймер-0", это означает, что он никогда не начинается официально, и он застревает в этой части. Первое правило выполнения потоков, НИКОГДА НЕ ИЗМЕНЯЙТЕ ЭЛЕМЕНТЫ UI ИЗ ВНЕШНЕГО интерфейса.. Я бы предложил использовать runOnUiThread
, как сказал йорк. Здесь ссылка о том, как ее использовать: runOnUiThread.
Довольно уверен, что TimerTask
- это runnable, означающее, что он работает в отдельном потоке. Меньше всего то, что я заметил в документах.
Ответ 5
Таким образом, это намного проще. Эта функция доступна на сайте разработчиков 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();
}
Ответ 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" [...]/>
[...]